package com.szcinda.service.dto.analysis;

import com.szcinda.repository.*;
import com.szcinda.service.DateUtils;
import com.szcinda.service.TypeStringUtils;
import com.szcinda.service.dto.organization.OrganizationService;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class OrderAnalysisServiceImpl implements OrderAnalysisService {

    private final Logger logger = LoggerFactory.getLogger(OrderAnalysisService.class);
    private final ZadOrderRepository zadOrderRepository;
    private final GhOrderRepository ghOrderRepository;
    private final CarrierRepository carrierRepository;
    private final ClientRepository clientRepository;
    private final OrderFeeRepository orderFeeRepository;
    private final BusinessCodeRepository businessCodeRepository;

    private final HistoryZadOrderRepository historyZadOrderRepository;
    private final HistoryGhOrderRepository historyGhOrderRepository;

    private final OrderFollowRepository orderFollowRepository;
    private final RateRepository rateRepository;
    private final UserRepository userRepository;
    private final LinePriceRepository linePriceRepository;
    private final OrganizationRepository organizationRepository;
    private final OrganizationService organizationService;
    private static final DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    public OrderAnalysisServiceImpl(ZadOrderRepository zadOrderRepository, GhOrderRepository ghOrderRepository, CarrierRepository carrierRepository, ClientRepository clientRepository, OrderFeeRepository orderFeeRepository, BusinessCodeRepository businessCodeRepository, HistoryZadOrderRepository historyZadOrderRepository, HistoryGhOrderRepository historyGhOrderRepository, OrderFollowRepository orderFollowRepository, RateRepository rateRepository, UserRepository userRepository, LinePriceRepository linePriceRepository, OrganizationRepository organizationRepository, OrganizationService organizationService) {
        this.zadOrderRepository = zadOrderRepository;
        this.ghOrderRepository = ghOrderRepository;
        this.carrierRepository = carrierRepository;
        this.clientRepository = clientRepository;
        this.orderFeeRepository = orderFeeRepository;
        this.businessCodeRepository = businessCodeRepository;
        this.historyZadOrderRepository = historyZadOrderRepository;
        this.historyGhOrderRepository = historyGhOrderRepository;
        this.orderFollowRepository = orderFollowRepository;
        this.rateRepository = rateRepository;
        this.userRepository = userRepository;
        this.linePriceRepository = linePriceRepository;
        this.organizationRepository = organizationRepository;
        this.organizationService = organizationService;
    }

    public static void main(String[] args) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        System.out.println(LocalDate.parse("2021-08-01", df).plusMonths(1));
    }

    @Override
    public List<ZadOrderAnalysisDto> queryZadOrderAnalysis(ZadOrderAnalysisQueryDto params) {
        boolean defualt = false;
        if (StringUtils.isEmpty(params.getCreateTimeStart()) || StringUtils.isEmpty(params.getCreateTimeEnd())) {
            defualt = true;
        }
        boolean finalDefualt = defualt;
        Specification<ZadOrder> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (finalDefualt) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()));
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1));
                predicates.add(timeEnd);
            } else {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeStart());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeEnd().plusDays(1));
                predicates.add(timeEnd);
            }

            if (!StringUtils.isEmpty(params.getOrganizationId())) {
                Predicate organizationId = criteriaBuilder.equal(root.get("organizationId").as(String.class), params.getOrganizationId());
                predicates.add(organizationId);
            }
            if (!StringUtils.isEmpty(params.getClientId())) {
                Predicate code = criteriaBuilder.equal(root.get("clientId").as(String.class), params.getClientId());
                predicates.add(code);
            }
            if (!StringUtils.isEmpty(params.getCarrierId())) {
                Carrier carrier = carrierRepository.findById(params.getCarrierId());
                Predicate carrierId = criteriaBuilder.like(root.get("carrierName").as(String.class), "%" + carrier.getName() + "%");
                predicates.add(carrierId);
            }
            if (!StringUtils.isEmpty(params.getBookName())) {
                Predicate bookName = criteriaBuilder.like(root.get("bookName").as(String.class), "%" + params.getBookName().trim() + "%");
                predicates.add(bookName);
            }
            if (!StringUtils.isEmpty(params.getOriginPlace())) {
                Predicate originPlace = criteriaBuilder.like(root.get("originPlace").as(String.class), "%" + params.getOriginPlace().trim() + "%");
                predicates.add(originPlace);
            }
            if (!StringUtils.isEmpty(params.getDestPlace())) {
                Predicate destPlace = criteriaBuilder.like(root.get("destPlace").as(String.class), "%" + params.getDestPlace().trim() + "%");
                predicates.add(destPlace);
            }
            if (!StringUtils.isEmpty(params.getUserName())) {
                Predicate userName = criteriaBuilder.like(root.get("userName").as(String.class), "%" + params.getUserName().trim() + "%");
                predicates.add(userName);
            }
            if (!StringUtils.isEmpty(params.getCabinetNumber())) {
                Predicate cabinetNumberArr = criteriaBuilder.like(root.get("cabinetNumberArr").as(String.class), "%" + params.getCabinetNumber().trim() + "%");
                predicates.add(cabinetNumberArr);
            }
            if (!StringUtils.isEmpty(params.getOrderNumber())) {
                Predicate orderNumber = criteriaBuilder.like(root.get("orderNumber").as(String.class), "%" + params.getOrderNumber().trim() + "%");
                predicates.add(orderNumber);
            }
            if (!StringUtils.isEmpty(params.getBusinessNumber())) {
                Predicate businessNumber = criteriaBuilder.like(root.get("businessNumber").as(String.class), "%" + params.getBusinessNumber().trim() + "%");
                predicates.add(businessNumber);
            }
            if (!StringUtils.isEmpty(params.getBookNumber())) {
                Predicate bookNumber = criteriaBuilder.like(root.get("bookNumber").as(String.class), "%" + params.getBookNumber().trim() + "%");
                predicates.add(bookNumber);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<ZadOrder> zadOrders = zadOrderRepository.findAll(specification);
        List<Client> clients = clientRepository.findAll();
        List<Carrier> carriers = carrierRepository.findAll();
        List<String> ids = zadOrders.stream().map(ZadOrder::getId).collect(Collectors.toList());
        List<OrderFee> orderFees = orderFeeRepository.findByOrderIdIn(ids);
        Map<String, List<ZadOrder>> group = zadOrders.stream().collect(Collectors.groupingBy(zadOrder -> fetchGroupKey(zadOrder.getCreateTime())));
        List<ZadOrderAnalysisDto> dtos = new ArrayList<>();
        TreeSet<String> dates = new TreeSet<>();
        dates.addAll(group.keySet());
        for (String date : dates) {
            ZadOrderAnalysisDto dto = new ZadOrderAnalysisDto();
            dto.setDate(date);
            dto.setId(UUID.randomUUID().toString());
            List<ZadOrder> zadOrderList = group.get(date);
            clients.forEach(client -> {
                List<String> orderIds = zadOrderList.stream().filter(zadOrder -> zadOrder.getClientId().equals(client.getId())).map(ZadOrder::getId).collect(Collectors.toList());
                List<OrderFee> orderFeeList = orderFees.stream().filter(orderFee -> orderIds.contains(orderFee.getOrderId()) && TypeStringUtils.feeInType.equals(orderFee.getType())).collect(Collectors.toList());
                orderFeeList.forEach(orderFee -> dto.addFee(orderFee, client.getName()));
            });
            carriers.forEach(carrier -> {
                List<String> orderIds = zadOrderList.stream().filter(zadOrder -> StringUtils.hasText(zadOrder.getCarrierName()) && zadOrder.getCarrierName().contains(carrier.getName())).map(ZadOrder::getId).collect(Collectors.toList());
                List<OrderFee> orderFeeList = orderFees.stream().filter(orderFee -> orderIds.contains(orderFee.getOrderId()) && TypeStringUtils.feeOutType.equals(orderFee.getType()) && carrier.getName().equals(orderFee.getCarrierId())).collect(Collectors.toList());
                orderFeeList.forEach(orderFee -> dto.addOutFee(orderFee, carrier.getName()));
            });
            dtos.add(dto);
        }
        return dtos;
    }

    private static String fetchGroupKey(LocalDateTime createTime) {
        return createTime.format(df);
    }

    @Override
    public List<GhOrderAnalysisDto> queryGhOrderAnalysis(GhOrderAnalysisQueryDto params) {
        boolean defualt = false;
        if (StringUtils.isEmpty(params.getCreateTimeStart()) || StringUtils.isEmpty(params.getCreateTimeEnd())) {
            defualt = true;
        }
        boolean finalDefualt = defualt;
        Specification<GhOrder> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (finalDefualt) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()));
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1));
                predicates.add(timeEnd);
            } else {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeStart());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeEnd().plusDays(1));
                predicates.add(timeEnd);
            }

            if (!StringUtils.isEmpty(params.getOrganizationId())) {
                Predicate organizationId = criteriaBuilder.equal(root.get("organizationId").as(String.class), params.getOrganizationId());
                predicates.add(organizationId);
            }
            if (!StringUtils.isEmpty(params.getClientId())) {
                Predicate client = criteriaBuilder.equal(root.get("clientId").as(String.class), params.getClientId());
                predicates.add(client);
            }
            if (!StringUtils.isEmpty(params.getCarrierId())) {
                Carrier carrier = carrierRepository.findById(params.getCarrierId());
                Predicate carrierId = criteriaBuilder.like(root.get("carrierName").as(String.class), "%" + carrier.getName() + "%");
                predicates.add(carrierId);
            }
            if (!StringUtils.isEmpty(params.getBookNumber())) {
                Predicate site = criteriaBuilder.like(root.get("bookNumber").as(String.class), "%" + params.getBookNumber().trim() + "%");
                predicates.add(site);
            }
            if (!StringUtils.isEmpty(params.getBookNumber())) {
                Predicate site = criteriaBuilder.like(root.get("bookNumber").as(String.class), "%" + params.getBookNumber().trim() + "%");
                predicates.add(site);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<GhOrder> ghOrders = ghOrderRepository.findAll(specification);
        List<GhOrderAnalysisDto> dtos = new ArrayList<>();
        List<Client> clients = clientRepository.findAll();
        List<Carrier> carriers = carrierRepository.findAll();
        List<String> ids = ghOrders.stream().map(GhOrder::getId).collect(Collectors.toList());
        List<OrderFee> orderFees = orderFeeRepository.findByOrderIdIn(ids);
        Map<String, List<GhOrder>> group = ghOrders.stream().collect(Collectors.groupingBy(ghOrder -> fetchGroupKey(ghOrder.getCreateTime())));
        TreeSet<String> dates = new TreeSet<>();
        dates.addAll(group.keySet());
        for (String date : dates) {
            GhOrderAnalysisDto dto = new GhOrderAnalysisDto();
            dto.setDate(date);
            dto.setId(UUID.randomUUID().toString());
            List<GhOrder> ghOrderList = group.get(date);
            clients.forEach(client -> {
                List<String> orderIds = ghOrderList.stream().filter(ghOrder -> ghOrder.getClientId().equals(client.getId())).map(GhOrder::getId).collect(Collectors.toList());
                List<OrderFee> orderFeeList = orderFees.stream().filter(orderFee -> orderIds.contains(orderFee.getOrderId()) && TypeStringUtils.feeInType.equals(orderFee.getType())).collect(Collectors.toList());
                orderFeeList.forEach(orderFee -> dto.addFee(orderFee, client.getName()));
                // 加上派送费
                ghOrderList.stream().filter(ghOrder -> ghOrder.getClientId().equals(client.getId())).forEach(ghOrder -> {
                    OrderFee fee = new OrderFee();
                    fee.setCurrency("人民币");
                    fee.setFeeName("车型派送费");
                    fee.setFeeCount(ghOrder.getDeliveryModelFee());
                    dto.addFee(fee, client.getName());
                });
            });
            carriers.forEach(carrier -> {
                List<String> orderIds = ghOrderList.stream().filter(ghOrder -> StringUtils.hasText(ghOrder.getCarrierName()) && ghOrder.getCarrierName().contains(carrier.getName())).map(GhOrder::getId).collect(Collectors.toList());
                List<OrderFee> orderFeeList = orderFees.stream().filter(orderFee -> orderIds.contains(orderFee.getOrderId()) && TypeStringUtils.feeOutType.equals(orderFee.getType()) && carrier.getName().equals(orderFee.getCarrierId())).collect(Collectors.toList());
                orderFeeList.forEach(orderFee -> dto.addOutFee(orderFee, carrier.getName()));
            });
            dtos.add(dto);
        }
        return dtos;
    }

    @Override
    public List<OrderProfitDto> queryProfit(GhOrderAnalysisQueryDto params) {
        List<OrderProfitDto> profitDtos = new ArrayList<>();
        List<Organization> organizations = organizationRepository.findByPrefixNotNull();
        if (params.getOrganizationIdList() != null && params.getOrganizationIdList().size() > 0) {
            organizations = organizations.stream().filter(organization -> params.getOrganizationIdList().contains(organization.getId())).collect(Collectors.toList());
        }
        List<Client> clients = clientRepository.findAll();
        if (!StringUtils.isEmpty(params.getClientId())) {
            clients = clients.stream().filter(client -> client.getId().equals(params.getClientId())).collect(Collectors.toList());
        }
        List<ExchangeRate> rates = rateRepository.findAll();
        // 过滤汇率有效期不在当前范围内的
        LocalDate now = LocalDate.now();
        rates = rates.stream().filter(rate -> rate.getStartDate() != null && rate.getEndDate() != null && rate.getStartDate().minusDays(1).isBefore(now) && now.isBefore(rate.getEndDate().plusDays(1))).collect(Collectors.toList());
        List<ClientData> clientDataList = new ArrayList<>();
        boolean defualt = false;
        if (StringUtils.isEmpty(params.getCreateTimeStart()) || StringUtils.isEmpty(params.getCreateTimeEnd())) {
            defualt = true;
        }
        boolean finalDefualt = defualt;
        for (Client client : clients) {
            ClientData clientData = new ClientData();
            clientData.setId(client.getId());
            clientData.setName(client.getName());
            // 财务账单统计逻辑：按照客户的机构过滤
            List<Organization> filterOrgs = organizations.stream().filter(organization -> client.getOrganizationId().equals(organization.getId())).collect(Collectors.toList());
            for (Organization organization : filterOrgs) {
                List<ZadOrder> zadOrders;
                List<GhOrder> ghOrders;
                Specification<ZadOrder> specification = ((root, criteriaQuery, criteriaBuilder) -> {
                    List<Predicate> predicates = new ArrayList<>();
                    Predicate organizationId = criteriaBuilder.equal(root.get("organizationId").as(String.class), organization.getId());
                    predicates.add(organizationId);
                    Predicate clientId = criteriaBuilder.equal(root.get("clientId"), client.getId());
                    predicates.add(clientId);
                    if (finalDefualt) {
                        Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()));
                        predicates.add(timeStart);
                        Predicate timeEnd = criteriaBuilder.lessThan(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1));
                        predicates.add(timeEnd);
                    } else {
                        Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeStart());
                        predicates.add(timeStart);
                        Predicate timeEnd = criteriaBuilder.lessThan(root.get("actDepartureTime"), params.getCreateTimeEnd().plusDays(1));
                        predicates.add(timeEnd);
                    }
                    if (!StringUtils.isEmpty(params.getCarrierId())) {
                        Predicate carrierId = criteriaBuilder.like(root.get("carrierName").as(String.class), "%" + params.getCarrierId() + "%");
                        predicates.add(carrierId);
                    }
                    return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
                });
                zadOrders = zadOrderRepository.findAll(specification);
                Specification<GhOrder> specification1 = ((root, criteriaQuery, criteriaBuilder) -> {
                    List<Predicate> predicates = new ArrayList<>();
                    Predicate organizationId = criteriaBuilder.equal(root.get("organizationId").as(String.class), organization.getId());
                    predicates.add(organizationId);
                    Predicate clientId = criteriaBuilder.equal(root.get("clientId"), client.getId());
                    predicates.add(clientId);
                    if (finalDefualt) {
                        Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()));
                        predicates.add(timeStart);
                        Predicate timeEnd = criteriaBuilder.lessThan(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1));
                        predicates.add(timeEnd);
                    } else {
                        Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeStart());
                        predicates.add(timeStart);
                        Predicate timeEnd = criteriaBuilder.lessThan(root.get("actDepartureTime"), params.getCreateTimeEnd().plusDays(1));
                        predicates.add(timeEnd);
                    }
                    if (!StringUtils.isEmpty(params.getCarrierId())) {
                        Predicate carrierId = criteriaBuilder.like(root.get("carrierName").as(String.class), "%" + params.getCarrierId() + "%");
                        predicates.add(carrierId);
                    }
                    return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
                });
                ghOrders = ghOrderRepository.findAll(specification1);
                List<String> ids = zadOrders.stream().map(ZadOrder::getId).collect(Collectors.toList());
                ids.addAll(ghOrders.stream().map(GhOrder::getId).collect(Collectors.toList()));
                List<OrderFee> orderFees = orderFeeRepository.findByOrderIdIn(ids);
                Set<String> carrierNames = orderFees.stream().filter(fee -> TypeStringUtils.feeOutType.equals(fee.getType()) && StringUtils.hasText(fee.getCarrierId()) && fee.getFeeCount() > 0).map(OrderFee::getCarrierId).collect(Collectors.toSet());
                // 计算应收 ，分两种情况1 不按供应商搜索2，按供应商搜索
                List<OrderFee> inFees = orderFees.stream().filter(fee -> TypeStringUtils.feeInType.equals(fee.getType()) && fee.getFeeCount() > 0).collect(Collectors.toList());
                boolean carrierQuery = StringUtils.hasText(params.getCarrierId());
                if (!carrierQuery && carrierNames.size() == 0) {
                    // 超期堆存费
                    for (ZadOrder zadOrder : zadOrders) {
                        if (zadOrder.getOverFee() > 0 && StringUtils.hasText(zadOrder.getOverFeeCurrency())) {
                            clientData.addInFee(zadOrder.getOverFeeCurrency(), "超期堆存费", zadOrder.getOverFee());
                            double value = getValueFromCurrency(rates, zadOrder.getOverFeeCurrency(), zadOrder.getOverFee());
                            clientData.setAmount(clientData.getAmount() + value);
                        }
                    }
                    for (OrderFee orderFee : inFees) {
                        clientData.addInFee(orderFee.getCurrency(), orderFee.getFeeName(), orderFee.getFeeCount());
                        if (StringUtils.hasText(orderFee.getCurrency()) && (orderFee.getCurrency().equals("人民币") || orderFee.getCurrency().equals("RMB"))) {
                            clientData.setAmount(clientData.getAmount() + orderFee.getFeeCount());
                        } else {
                            double value = getValueFromCurrency(rates, orderFee.getCurrency(), orderFee.getFeeCount());
                            clientData.setAmount(clientData.getAmount() + value);
                        }
                    }
                    OrderProfitDto dto = new OrderProfitDto();
                    dto.setId(UUID.randomUUID().toString());
                    dto.setClientId(client.getId());
                    dto.setClientName(client.getName());
                    dto.setOrganizationName(organization.getName());
                    profitDtos.add(dto);
                } else {
                    // 过滤需要查询的供应商
                    if (StringUtils.hasText(params.getCarrierId())) {
                        carrierNames = carrierNames.stream().filter(name -> name.equals(params.getCarrierId())).collect(Collectors.toSet());
                    }
                    // 如果供应商列表为空, 则跳过
                    if (carrierNames.size() == 0) continue;
                    // 超期堆存费
                    for (ZadOrder zadOrder : zadOrders) {
                        if (zadOrder.getOverFee() > 0 && StringUtils.hasText(zadOrder.getOverFeeCurrency())) {
                            clientData.addInFee(zadOrder.getOverFeeCurrency(), "超期堆存费", zadOrder.getOverFee());
                            double value = getValueFromCurrency(rates, zadOrder.getOverFeeCurrency(), zadOrder.getOverFee());
                            clientData.setAmount(clientData.getAmount() + value);
                        }
                    }
                    for (OrderFee orderFee : inFees) {
                        clientData.addInFee(orderFee.getCurrency(), orderFee.getFeeName(), orderFee.getFeeCount());
                        if (StringUtils.hasText(orderFee.getCurrency()) && (orderFee.getCurrency().equals("人民币") || orderFee.getCurrency().equals("RMB"))) {
                            clientData.setAmount(clientData.getAmount() + orderFee.getFeeCount());
                        } else {
                            double value = getValueFromCurrency(rates, orderFee.getCurrency(), orderFee.getFeeCount());
                            clientData.setAmount(clientData.getAmount() + value);
                        }
                    }
                    for (String carrierName : carrierNames) {
                        OrderProfitDto dto = new OrderProfitDto();
                        // 计算应付
                        List<OrderFee> outFees = orderFees.stream().filter(fee -> TypeStringUtils.feeOutType.equals(fee.getType()) && StringUtils.hasText(fee.getCarrierId()) && fee.getCarrierId().equals(carrierName)).collect(Collectors.toList());
                        for (OrderFee outFee : outFees) {
                            dto.addOutFee(outFee.getCurrency(), outFee.getFeeName(), outFee.getFeeCount());
                            if (StringUtils.hasText(outFee.getCurrency()) && (outFee.getCurrency().equals("人民币") || outFee.getCurrency().equals("RMB"))) {
                                dto.setOutAmount(dto.getOutAmount() + outFee.getFeeCount());
                            } else {
                                double value = getValueFromCurrency(rates, outFee.getCurrency(), outFee.getFeeCount());
                                dto.setOutAmount(dto.getOutAmount() + value);
                            }
                        }
                        dto.setId(UUID.randomUUID().toString());
                        dto.setClientId(client.getId());
                        dto.setClientName(client.getName());
                        dto.setOrganizationName(organization.getName());
                        dto.setCarrierName(carrierName);
                        profitDtos.add(dto);
                    }
                }
            }
            clientDataList.add(clientData);
        }
        // 汇总金额
        for (OrderProfitDto profitDto : profitDtos) {
            clientDataList.stream().filter(clientData -> clientData.getId().equals(profitDto.getClientId())).findFirst().ifPresent(clientData -> {
                profitDto.setInAmount(clientData.getAmount());
                profitDto.setInTransportFeeOfRMB(clientData.getInTransportFeeOfRMB());
                profitDto.setInTransportFeeOfUSD(clientData.getInTransportFeeOfUSD());
                profitDto.setInOtherOfRMB(clientData.getInOtherOfRMB());
                profitDto.setInOtherOfUSD(clientData.getInOtherOfUSD());
            });
        }
        // 汇总 应付金额
        Map<String, List<OrderProfitDto>> listMap = profitDtos.stream().collect(Collectors.groupingBy(OrderProfitDto::getClientId));
        Set<String> keySet = listMap.keySet();
        for (String clientId : keySet) {
            List<OrderProfitDto> dtos = listMap.get(clientId);
            ClientData data = clientDataList.stream().filter(clientData -> clientData.getId().equals(clientId)).findFirst().orElse(null);
            if (data == null) continue;
            double amount = data.getAmount();
            for (OrderProfitDto dto : dtos) {
                amount -= dto.getOutAmount();
            }
            data.setProfit(amount);
        }
        // 利润
        for (OrderProfitDto profitDto : profitDtos) {
            clientDataList.stream().filter(clientData -> clientData.getId().equals(profitDto.getClientId())).findFirst().ifPresent(clientData -> profitDto.setProfit(clientData.getProfit()));
        }
        // 加总和
        OrderProfitDto total = new OrderProfitDto();
        total.setClientName("总和");
        for (ClientData clientData : clientDataList) {
            total.setInTransportFeeOfRMB(total.getInTransportFeeOfRMB() + clientData.getInTransportFeeOfRMB());
            total.setInTransportFeeOfUSD(total.getInTransportFeeOfUSD() + clientData.getInTransportFeeOfUSD());
            total.setInOtherOfRMB(total.getInOtherOfRMB() + clientData.getInOtherOfRMB());
            total.setInOtherOfUSD(total.getInOtherOfUSD() + clientData.getInOtherOfUSD());
            total.setInAmount(total.getInAmount() + clientData.getAmount());
            total.setProfit(total.getProfit() + clientData.getProfit());
        }
        for (OrderProfitDto profitDto : profitDtos) {
            total.setOutTransportFeeOfRMB(total.getOutTransportFeeOfRMB() + profitDto.getOutTransportFeeOfRMB());
            total.setOutTransportFeeOfUSD(total.getOutTransportFeeOfUSD() + profitDto.getOutTransportFeeOfUSD());
            total.setOutOtherOfRMB(total.getOutOtherOfRMB() + profitDto.getOutOtherOfRMB());
            total.setOutOtherOfUSD(total.getOutOtherOfUSD() + profitDto.getOutOtherOfUSD());
            total.setOutAmount(total.getOutAmount() + profitDto.getOutAmount());
        }
        profitDtos.add(total);
        return profitDtos;
    }


    public static double getValueFromCurrency(List<ExchangeRate> rates, String currency, double amount) {
        if (rates == null) {
            return 0;
        }
        ExchangeRate exchangeRate = rates.stream().filter(rate -> rate.getFromRate().equals(currency) || (rate.getFromRate().equals("人民币") || rate.getFromRate().equals("RMB")) || rate.getToRate().equals(currency) && (rate.getToRate().equals("人民币") || rate.getToRate().equals("RMB"))).findFirst().orElse(null);
        if (exchangeRate != null) {
            // 币种转换运算
            // 正方向
//            if (exchangeRate.getFromRate().equals(currency) && (exchangeRate.getToRate().equals("人民币") || exchangeRate.getToRate().equals("RMB"))) {
//                BigDecimal b1 = BigDecimal.valueOf(amount);
//                BigDecimal b2 = BigDecimal.valueOf(exchangeRate.getRate());
//                return b1.multiply(b2).doubleValue();
//            } else {
//                // 反方向
//                BigDecimal b1 = BigDecimal.valueOf(amount);
//                BigDecimal b2 = BigDecimal.valueOf(exchangeRate.getRate());
//                return b1.divide(b2, 2, RoundingMode.HALF_DOWN).doubleValue();
//            }
            BigDecimal b1 = BigDecimal.valueOf(amount);
            BigDecimal b2 = BigDecimal.valueOf(exchangeRate.getRate());
            return b1.multiply(b2).doubleValue();
        }
        return 0;
    }

    @Override
    public List<CargoDataDto> cargoQuery(GhOrderAnalysisQueryDto params) {
        List<CargoDataDto> cargoDataDtos = new ArrayList<>();
        boolean finalDefualt = StringUtils.isEmpty(params.getCreateTimeStart()) || StringUtils.isEmpty(params.getCreateTimeEnd());
        Specification<ZadOrder> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (finalDefualt) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()));
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1));
                predicates.add(timeEnd);
            } else {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeStart());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeEnd().plusDays(1));
                predicates.add(timeEnd);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<ZadOrder> zadOrders = zadOrderRepository.findAll(specification);
        List<Client> clients = clientRepository.findAll(zadOrders.stream().map(ZadOrder::getClientId).collect(Collectors.toSet()));
        for (Client client : clients) {
            CargoDataDto dto = new CargoDataDto();
            dto.setClientName(client.getName());
            List<ZadOrder> orders = zadOrders.stream().filter(zadOrder -> zadOrder.getClientId().equals(client.getId())).collect(Collectors.toList());
            for (ZadOrder order : orders) {
                dto.addItem(order.getGoodsName(), order.getGoodsWeight());
            }
            cargoDataDtos.add(dto);
        }

        List<CargoDataDto> cargoDataDtos2 = new ArrayList<>();
        for (CargoDataDto cargoDataDto : cargoDataDtos) {
            List<CargoDataDto.Item> items = cargoDataDto.getItems();
            for (CargoDataDto.Item item : items) {
                CargoDataDto dto = new CargoDataDto();
                dto.setClientName(cargoDataDto.getClientName());
                dto.setGoodsName(item.getGoodsName());
                dto.setGoodsWeight(item.getGoodsWeight());
                cargoDataDtos2.add(dto);
            }
        }
        return cargoDataDtos2;
    }

    @Override
    public List<BusinessDataDto> businessQuery(GhOrderAnalysisQueryDto params) {
        List<BusinessCode> businessCodes = businessCodeRepository.findAll();
        List<BusinessDataDto> dataDto = new ArrayList<>();
        businessCodes.forEach(businessCode -> {
            BusinessDataDto dto = new BusinessDataDto();
            dto.setBusinessName(businessCode.getName());
            boolean finalDefualt = StringUtils.isEmpty(params.getCreateTimeStart()) || StringUtils.isEmpty(params.getCreateTimeEnd());
            Specification<ZadOrder> specification = ((root, criteriaQuery, criteriaBuilder) -> {
                List<Predicate> predicates = new ArrayList<>();
                if (finalDefualt) {
                    Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()));
                    predicates.add(timeStart);
                    Predicate timeEnd = criteriaBuilder.lessThan(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1));
                    predicates.add(timeEnd);
                } else {
                    Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeStart());
                    predicates.add(timeStart);
                    Predicate timeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeEnd().plusDays(1));
                    predicates.add(timeEnd);
                }
                Predicate businessId = criteriaBuilder.equal(root.get("businessCode"), businessCode.getName());
                predicates.add(businessId);
                return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
            });
            dto.setCount(zadOrderRepository.findAll(specification).size());
            Specification<GhOrder> specification2 = ((root, criteriaQuery, criteriaBuilder) -> {
                List<Predicate> predicates = new ArrayList<>();
                if (finalDefualt) {
                    Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()));
                    predicates.add(timeStart);
                    Predicate timeEnd = criteriaBuilder.lessThan(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1));
                    predicates.add(timeEnd);
                } else {
                    Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeStart());
                    predicates.add(timeStart);
                    Predicate timeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeEnd().plusDays(1));
                    predicates.add(timeEnd);
                }
                Predicate businessId = criteriaBuilder.equal(root.get("businessCode"), businessCode.getName());
                predicates.add(businessId);
                return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
            });
            dto.setCount(dto.getCount() + ghOrderRepository.findAll(specification2).size());
            dataDto.add(dto);
        });
        return dataDto;
    }

    @Override
    public List<LineDataDto> lineQuery(GhOrderAnalysisQueryDto params) {
        List<LineDataDto> lineDataDtos = new ArrayList<>();
        boolean defualt = false;
        if (StringUtils.isEmpty(params.getCreateTimeStart()) || StringUtils.isEmpty(params.getCreateTimeEnd())) {
            defualt = true;
        }
        boolean finalDefualt = defualt;
        Specification<ZadOrder> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (finalDefualt) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()));
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1));
                predicates.add(timeEnd);
            } else {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeStart());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeEnd().plusDays(1));
                predicates.add(timeEnd);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<ZadOrder> zadOrders = zadOrderRepository.findAll(specification);
        for (ZadOrder zadOrder : zadOrders) {
            if (StringUtils.hasText(zadOrder.getOriginPlace()) && StringUtils.hasText(zadOrder.getDestPlace())) {
                String text = zadOrder.getOriginPlace() + "->" + zadOrder.getDestPlace();
                LineDataDto dataDto = lineDataDtos.stream().filter(lineDataDto -> lineDataDto.getLine().equals(text)).findFirst().orElse(null);
                if (dataDto == null) {
                    dataDto = new LineDataDto();
                    dataDto.setLine(text);
                    dataDto.setCount(1);
                    lineDataDtos.add(dataDto);
                } else {
                    dataDto.setCount(dataDto.getCount() + 1);
                }
            }
        }
        return lineDataDtos;
    }

    @Override
    public List<UserOperateDataDto> operateQuery(GhOrderAnalysisQueryDto params) {
        List<UserOperateDataDto> dataDtos = new ArrayList<>();
        List<Organization> organizations = organizationRepository.findAll();
        for (Organization organization : organizations) {
            List<User> users = userRepository.findByOrganizationId(organization.getId());
            for (User user : users) {
                UserOperateDataDto dataDto = new UserOperateDataDto();
                boolean defualt = StringUtils.isEmpty(params.getCreateTimeStart()) || StringUtils.isEmpty(params.getCreateTimeEnd());
                Specification<ZadOrder> specification = ((root, criteriaQuery, criteriaBuilder) -> {
                    List<Predicate> predicates = new ArrayList<>();
                    Predicate organizationId = criteriaBuilder.equal(root.get("userId").as(String.class), user.getId());
                    predicates.add(organizationId);
                    if (defualt) {
                        Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay());
                        predicates.add(timeStart);
                        Predicate timeEnd = criteriaBuilder.lessThan(root.get("createTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1).atStartOfDay());
                        predicates.add(timeEnd);
                    } else {
                        Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), params.getCreateTimeStart().atStartOfDay());
                        predicates.add(timeStart);
                        Predicate timeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), params.getCreateTimeEnd().plusDays(1).atStartOfDay());
                        predicates.add(timeEnd);
                    }
                    return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
                });
                List<ZadOrder> zadOrders = zadOrderRepository.findAll(specification);
                Specification<GhOrder> specification2 = ((root, criteriaQuery, criteriaBuilder) -> {
                    List<Predicate> predicates = new ArrayList<>();
                    Predicate organizationId = criteriaBuilder.equal(root.get("userId").as(String.class), user.getId());
                    predicates.add(organizationId);
                    if (defualt) {
                        Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay());
                        predicates.add(timeStart);
                        Predicate timeEnd = criteriaBuilder.lessThan(root.get("createTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1).atStartOfDay());
                        predicates.add(timeEnd);
                    } else {
                        Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), params.getCreateTimeStart().atStartOfDay());
                        predicates.add(timeStart);
                        Predicate timeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), params.getCreateTimeEnd().plusDays(1).atStartOfDay());
                        predicates.add(timeEnd);
                    }
                    return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
                });
                List<GhOrder> ghOrders = ghOrderRepository.findAll(specification2);

                dataDto.setOrganizationName(organization.getName());
                dataDto.setUserName(user.getAccount());
                dataDto.setCount(zadOrders.size() + ghOrders.size());
                dataDtos.add(dataDto);
            }
        }
        Map<String, Integer> map = new HashMap<>();
        int total = 0;
        for (UserOperateDataDto dataDto : dataDtos) {
            if (map.containsKey(dataDto.getOrganizationName())) {
                map.put(dataDto.getOrganizationName(), map.get(dataDto.getOrganizationName()) + dataDto.getCount());
            } else {
                map.put(dataDto.getOrganizationName(), dataDto.getCount());
            }
            total += dataDto.getCount();
        }
        for (UserOperateDataDto dataDto : dataDtos) {
            dataDto.setOrgCount(map.get(dataDto.getOrganizationName()));
        }
        UserOperateDataDto totalDto = new UserOperateDataDto();
        totalDto.setOrganizationName("总和");
        totalDto.setOrgCount(total);
        dataDtos.add(totalDto);
        return dataDtos;
    }


    @Override
    public List<OrderCountDto> clientCountQuery(GhOrderAnalysisQueryDto params) {
        List<OrderCountDto> countDtos = new ArrayList<>();
        List<Client> clients = clientRepository.findAll();
        boolean defualt = StringUtils.isEmpty(params.getCreateTimeStart()) || StringUtils.isEmpty(params.getCreateTimeEnd());
        for (Client client : clients) {
            OrderCountDto dto = new OrderCountDto(client.getName(), 0);
            Specification<ZadOrder> specification = ((root, criteriaQuery, criteriaBuilder) -> {
                List<Predicate> predicates = new ArrayList<>();
                Predicate clientId = criteriaBuilder.equal(root.get("clientId").as(String.class), client.getId());
                predicates.add(clientId);
                if (defualt) {
                    Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()));
                    predicates.add(timeStart);
                    Predicate timeEnd = criteriaBuilder.lessThan(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1));
                    predicates.add(timeEnd);
                } else {
                    Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeStart());
                    predicates.add(timeStart);
                    Predicate timeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeEnd().plusDays(1));
                    predicates.add(timeEnd);
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
            });
            List<ZadOrder> zadOrders = zadOrderRepository.findAll(specification);
            dto.setCount(zadOrders.size());
            Specification<GhOrder> specification2 = ((root, criteriaQuery, criteriaBuilder) -> {
                List<Predicate> predicates = new ArrayList<>();
                Predicate clientId = criteriaBuilder.equal(root.get("clientId").as(String.class), client.getId());
                predicates.add(clientId);
                if (defualt) {
                    Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()));
                    predicates.add(timeStart);
                    Predicate timeEnd = criteriaBuilder.lessThan(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1));
                    predicates.add(timeEnd);
                } else {
                    Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeStart());
                    predicates.add(timeStart);
                    Predicate timeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeEnd().plusDays(1));
                    predicates.add(timeEnd);
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
            });
            List<GhOrder> ghOrders = ghOrderRepository.findAll(specification2);
            dto.setCount(dto.getCount() + ghOrders.size());
            if (dto.getCount() > 0) {
                countDtos.add(dto);
            }
        }
        return countDtos;
    }

    @Override
    public List<OrderCountDto> carrierOrderQuery(GhOrderAnalysisQueryDto params) {
        List<OrderCountDto> countDtos = new ArrayList<>();
        boolean defualt = false;
        if (StringUtils.isEmpty(params.getCreateTimeStart()) || StringUtils.isEmpty(params.getCreateTimeEnd())) {
            defualt = true;
        }
        List<Carrier> carriers = carrierRepository.findAll();
        for (Carrier carrier : carriers) {
            OrderCountDto dto = new OrderCountDto(carrier.getName(), 0);
            boolean finalDefualt = defualt;
            Specification<OrderFee> specification = ((root, criteriaQuery, criteriaBuilder) -> {
                List<Predicate> predicates = new ArrayList<>();
                Predicate organizationId = criteriaBuilder.equal(root.get("carrierId").as(String.class), carrier.getName());
                predicates.add(organizationId);
                if (finalDefualt) {
                    Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay());
                    predicates.add(timeStart);
                    Predicate timeEnd = criteriaBuilder.lessThan(root.get("createTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1).atStartOfDay());
                    predicates.add(timeEnd);
                } else {
                    Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), params.getCreateTimeStart().atStartOfDay());
                    predicates.add(timeStart);
                    Predicate timeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), params.getCreateTimeEnd().plusDays(1).atStartOfDay());
                    predicates.add(timeEnd);
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
            });
            List<OrderFee> orderFees = orderFeeRepository.findAll(specification);
            Set<String> orderCountSet = orderFees.stream().map(OrderFee::getOrderId).collect(Collectors.toSet());
            dto.setCount(orderCountSet.size());
            if (dto.getCount() > 0) {
                countDtos.add(dto);
            }
        }
        return countDtos;
    }

    @Override
    public List<LinePriceDataDto> clientPriceQuery(GhOrderAnalysisQueryDto params) {
        boolean defualt = StringUtils.isEmpty(params.getCreateTimeStart()) || StringUtils.isEmpty(params.getCreateTimeEnd());
        Specification<ZadOrder> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (defualt) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()));
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1));
                predicates.add(timeEnd);
            } else {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeStart());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeEnd().plusDays(1));
                predicates.add(timeEnd);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<ZadOrder> zadOrders = zadOrderRepository.findAll(specification);
        Specification<GhOrder> specification2 = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (defualt) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()));
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("actDepartureTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1));
                predicates.add(timeEnd);
            } else {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeStart());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("actDepartureTime"), params.getCreateTimeEnd().plusDays(1));
                predicates.add(timeEnd);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<GhOrder> ghOrders = ghOrderRepository.findAll(specification2);
        Set<String> lines = zadOrders.stream().map(order -> order.getOriginPlace() + "->" + order.getDestPlace()).collect(Collectors.toSet());
        lines.addAll(ghOrders.stream().map(order -> order.getOriginPlace() + "->" + order.getDestPlace()).collect(Collectors.toSet()));
        List<LinePriceDataDto> linePriceDataDtos = new ArrayList<>();
        List<Client> clients = clientRepository.findAll();
        List<LinePrice> linePrices = linePriceRepository.findByBelongIdIn(clients.stream().map(Client::getId).collect(Collectors.toList()));
        String line;
        for (LinePrice linePrice : linePrices) {
            Client client = clients.stream().filter(c -> c.getId().equals(linePrice.getBelongId())).findFirst().orElse(null);
            if (client == null) {
                continue;
            }
            LinePriceDataDto dto = new LinePriceDataDto();
            dto.setName(client.getName());
            line = linePrice.getOriginPlace() + "->" + linePrice.getDestPlace();
            if (lines.contains(line)) {
                dto.setLine(line);
                dto.setPrice(linePrice.getPrice());
                dto.setBusiness(linePrice.getBusinessType());
                dto.setCurrency(linePrice.getCurrency());
                dto.setFeeName(linePrice.getFeeName());
                dto.setCalculateType(CalculateTypeUtil.getCalculateTypeString(linePrice.getCalculateType()));
                linePriceDataDtos.add(dto);
            }
        }
        return linePriceDataDtos;
    }

    @Override
    public List<LinePriceDataDto> carrierPriceQuery(GhOrderAnalysisQueryDto params) {
        boolean defualt = StringUtils.isEmpty(params.getCreateTimeStart()) || StringUtils.isEmpty(params.getCreateTimeEnd());
        Specification<OrderFee> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (defualt) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()).atStartOfDay());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("createTime"), LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()).plusMonths(1).atStartOfDay());
                predicates.add(timeEnd);
            } else {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"), params.getCreateTimeStart().atStartOfDay());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThanOrEqualTo(root.get("createTime"), params.getCreateTimeEnd().plusDays(1).atStartOfDay());
                predicates.add(timeEnd);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<OrderFee> orderFees = orderFeeRepository.findAll(specification);
        Set<String> orderCountSet = orderFees.stream().map(OrderFee::getOrderId).collect(Collectors.toSet());
        List<ZadOrder> zadOrders = zadOrderRepository.findAll(orderCountSet);
        List<GhOrder> ghOrders = ghOrderRepository.findAll(orderCountSet);
        Set<String> lines = zadOrders.stream().map(order -> order.getOriginPlace() + "->" + order.getDestPlace()).collect(Collectors.toSet());
        lines.addAll(ghOrders.stream().map(order -> order.getOriginPlace() + "->" + order.getDestPlace()).collect(Collectors.toSet()));
        List<LinePriceDataDto> linePriceDataDtos = new ArrayList<>();
        List<Carrier> carriers = carrierRepository.findAll();
        List<LinePrice> linePrices = linePriceRepository.findByBelongIdIn(carriers.stream().map(Carrier::getId).collect(Collectors.toList()));
        String line;
        for (LinePrice linePrice : linePrices) {
            Carrier carrier = carriers.stream().filter(c -> c.getId().equals(linePrice.getBelongId())).findFirst().orElse(null);
            if (carrier == null) {
                continue;
            }
            LinePriceDataDto dto = new LinePriceDataDto();
            dto.setName(carrier.getName());
            line = linePrice.getOriginPlace() + "->" + linePrice.getDestPlace();
            if (lines.contains(line)) {
                dto.setLine(line);
                dto.setPrice(linePrice.getPrice());
                dto.setBusiness(linePrice.getBusinessType());
                dto.setCurrency(linePrice.getCurrency());
                dto.setFeeName(linePrice.getFeeName());
                dto.setCalculateType(CalculateTypeUtil.getCalculateTypeString(linePrice.getCalculateType()));
                linePriceDataDtos.add(dto);
            }
        }
        return linePriceDataDtos;
    }

    public static String getCurrentYear() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
        Date date = new Date();
        return sdf.format(date);
    }

    // 班列业务分析
    @Override
    public ZadOrderYearCountDto zadOrderCount(ZadOrderAnalysisQueryDto params) {
        ZadOrderYearCountDto yearCountDto = new ZadOrderYearCountDto();
        // 得到当前机构及子机构的所有订单
        List<String> orgIds = organizationService.getChildOrgIds(params.getOrganizationId());
        if (StringUtils.isEmpty(params.getYear())) {
            params.setYear(getCurrentYear());
        }
        Specification<ZadOrder> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            // 下一年
            int nextYear = Integer.parseInt(params.getYear()) + 1;
            String startDate;
            String endDate;
            if (StringUtils.isEmpty(params.getType()) || "1".equals(params.getType())) {
                startDate = params.getYear() + "-01-01";
                endDate = nextYear + "-01-01";
            } else {
                startDate = params.getCreateTimeStart().format(df);
                endDate = params.getCreateTimeEnd().plusDays(1).format(df);
            }
            Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("preDepartureTime"), LocalDate.parse(startDate, DateTimeFormatter.ISO_DATE));
            predicates.add(timeStart);
            Predicate timeEnd = criteriaBuilder.lessThan(root.get("preDepartureTime"), LocalDate.parse(endDate, DateTimeFormatter.ISO_DATE));
            predicates.add(timeEnd);
            Expression<String> exp = root.get("organizationId");
            predicates.add(exp.in(orgIds));
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<ZadOrder> zadOrders = zadOrderRepository.findAll(specification);
        // 归还状态
        yearCountDto.getReturnList().add(new OrderCountDto("超期未还", 0));
        yearCountDto.getReturnList().add(new OrderCountDto("正常归还", 0));
        for (ZadOrder zadOrder : zadOrders) {
            List<OrderFollow> orderFollows = orderFollowRepository.findByOrderId(zadOrder.getId());
            // 统计SOC、COC、租箱
            if (zadOrder.getDestPlace().toLowerCase().contains("coc") && !zadOrder.getDestPlace().toLowerCase().contains("纯coc")) {
                yearCountDto.getSoccocCountDto().setCocCount(yearCountDto.getSoccocCountDto().getCocCount() + 1);
            } else if (zadOrder.getDestPlace().toLowerCase().contains("纯coc")) {
                yearCountDto.getSoccocCountDto().setZxCount(yearCountDto.getSoccocCountDto().getZxCount() + 1);
            } else if (!zadOrder.getDestPlace().toLowerCase().contains("cos") && !zadOrder.getDestPlace().toLowerCase().contains("纯coc")) {
                yearCountDto.getSoccocCountDto().setSocCount(yearCountDto.getSoccocCountDto().getSocCount() + 1);
            }
            // 获取当前时间的月份
            int monthValue = zadOrder.getPreDepartureTime().getMonthValue();
            // 拼接起始站和目的站
            String line = zadOrder.getOriginPlace().toLowerCase().replace("纯", "").replace("coc", "").replace("soc", "") + zadOrder.getDestPlace().toLowerCase().replace("纯", "").replace("coc", "").replace("soc", "");
            // 计算相同线路的时效
            if (orderFollows.size() > 0 && orderFollows.get(0).getArriveTime() != null && zadOrder.getActDepartureTime() != null) {
                // 计算两个日期相差多少天
                Duration duration = Duration.between(orderFollows.get(0).getArriveTime(), zadOrder.getActDepartureTime().atStartOfDay());
                long days = Math.abs(duration.toDays()); //相差的天数
                if (yearCountDto.getLineAgeList().stream().noneMatch(item -> item.getLine().equals(line) && item.getMonth() == monthValue)) {
                    LineAgeDto lineAgeDto = new LineAgeDto();
                    lineAgeDto.setLine(line);
                    lineAgeDto.setMonth(monthValue);
                    lineAgeDto.setCount(1);
                    lineAgeDto.setAge(days);
                    yearCountDto.getLineAgeList().add(lineAgeDto);
                } else {
                    yearCountDto.getLineAgeList().stream().filter(item -> item.getLine().equals(line) && item.getMonth() == monthValue).findFirst().ifPresent(item -> {
                        item.setCount(item.getCount() + 1);
                        item.setAge(item.getAge() + days);
                    });
                }
            }
            // 统计报关方式
            if (StringUtils.hasText(zadOrder.getCustomsType())) {
                if (yearCountDto.getBgList().stream().noneMatch(item -> item.getName().equals(zadOrder.getCustomsType()))) {
                    yearCountDto.getBgList().add(new OrderCountDto(zadOrder.getCustomsType(), 1));
                } else {
                    yearCountDto.getBgList().stream().filter(item -> item.getName().equals(zadOrder.getCustomsType())).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
                }
            }
            // 统计出境口岸
            if (StringUtils.hasText(zadOrder.getCarrierDeparturePort())) {
                if (yearCountDto.getKaList().stream().noneMatch(item -> item.getName().equals(zadOrder.getCarrierDeparturePort()))) {
                    yearCountDto.getKaList().add(new OrderCountDto(zadOrder.getCarrierDeparturePort(), 1));
                } else {
                    yearCountDto.getKaList().stream().filter(item -> item.getName().equals(zadOrder.getCarrierDeparturePort())).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
                }
            }
            // 统计货物品类
            if (StringUtils.hasText(zadOrder.getGoodsName())) {
                if (yearCountDto.getPlList().stream().noneMatch(item -> item.getName().equals(zadOrder.getGoodsName()))) {
                    yearCountDto.getPlList().add(new OrderCountDto(zadOrder.getGoodsName(), 1));
                } else {
                    yearCountDto.getPlList().stream().filter(item -> item.getName().equals(zadOrder.getGoodsName())).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
                }
            }
            // 租箱点统计
            if (StringUtils.hasText(zadOrder.getPickPlace())) {
                if (yearCountDto.getZxdList().stream().noneMatch(item -> item.getName().equals(zadOrder.getPickPlace()))) {
                    yearCountDto.getZxdList().add(new OrderCountDto(zadOrder.getPickPlace(), 1));
                } else {
                    yearCountDto.getZxdList().stream().filter(item -> item.getName().equals(zadOrder.getPickPlace())).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
                }
            }

            // 根据“还箱日期”减去“发车日期”判断，大于35天，属于超期归还，小于等于35天属于正常归还（空值不计算）
            if (zadOrder.getPackageReturnDate() != null && zadOrder.getActDepartureTime() != null) {
                // 计算两个日期相差多少天
                Duration duration = Duration.between(zadOrder.getActDepartureTime().atStartOfDay(), zadOrder.getPackageReturnDate().atStartOfDay());
                long days = duration.toDays(); //相差的天数
                if (days > 35) {
                    yearCountDto.getReturnList().stream().filter(item -> item.getName().equals("超期未还")).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
                } else {
                    yearCountDto.getReturnList().stream().filter(item -> item.getName().equals("正常归还")).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
                }
            }
            // 统计相同起始站内，不同目的站的订单数
            if (StringUtils.hasText(zadOrder.getOriginPlace()) && StringUtils.hasText(zadOrder.getDestPlace())) {
                String text = zadOrder.getOriginPlace();
                if (yearCountDto.getSameStartPlaceList().stream().noneMatch(item -> item.getStartPlace().equals(text))) {
                    StartPlaceCountDto countDto = new StartPlaceCountDto(text);
                    countDto.getEndList().add(new OrderCountDto(zadOrder.getDestPlace(), 1));
                    yearCountDto.getSameStartPlaceList().add(countDto);
                } else {
                    String text2 = zadOrder.getDestPlace();
                    yearCountDto.getSameStartPlaceList().stream().filter(item -> item.getStartPlace().equals(text)).findFirst().flatMap(item -> item.getEndList().stream().filter(item2 -> item2.getName().equals(text2)).findFirst()).ifPresent(item2 -> item2.setCount(item2.getCount() + 1));
                }
            }
        }
        // 国际版列历史
        Specification<HistoryZadOrder> specification3 = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (params.getCreateTimeStart() != null && params.getCreateTimeEnd() != null) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("blTime"), params.getCreateTimeStart());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("blTime"), params.getCreateTimeEnd().plusDays(1));
                predicates.add(timeEnd);
            }
            // 得到当前机构及子机构的所有订单
            Expression<String> exp = root.get("organizationId");
            predicates.add(exp.in(orgIds));
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<HistoryZadOrder> historyZadOrderRepositoryAll = historyZadOrderRepository.findAll(specification3);
        // 先按照柜号进行分组
        Map<String, List<HistoryZadOrder>> historyZadOrderRepositoryAllMap =
                historyZadOrderRepositoryAll.stream().filter(data -> StringUtils.hasText(data.getClientName())).collect(Collectors.groupingBy(HistoryZadOrder::getPackageNo));
        Set<String> packageMapList = historyZadOrderRepositoryAllMap.keySet();
        LocalDateTime localDateTime;
        for (String packageNo : packageMapList) {
            HistoryZadOrder zadOrder = historyZadOrderRepositoryAllMap.get(packageNo).get(0);
            if(StringUtils.hasText(zadOrder.getDestPlace())){
                // 统计SOC、COC、租箱
                if ( zadOrder.getDestPlace().toLowerCase().contains("coc") && !zadOrder.getDestPlace().toLowerCase().contains("纯coc")) {
                    yearCountDto.getSoccocCountDto().setCocCount(yearCountDto.getSoccocCountDto().getCocCount() + 1);
                } else if (zadOrder.getDestPlace().toLowerCase().contains("纯coc")) {
                    yearCountDto.getSoccocCountDto().setZxCount(yearCountDto.getSoccocCountDto().getZxCount() + 1);
                } else if (!zadOrder.getDestPlace().toLowerCase().contains("cos") && !zadOrder.getDestPlace().toLowerCase().contains("纯coc")) {
                    yearCountDto.getSoccocCountDto().setSocCount(yearCountDto.getSoccocCountDto().getSocCount() + 1);
                }
            }
            // 获取当前时间的月份
            int monthValue = zadOrder.getBlTime().getMonthValue();
            // 拼接起始站和目的站
            if(StringUtils.hasText(zadOrder.getStartPlace()) && StringUtils.hasText(zadOrder.getDestPlace())){
                String line =
                        zadOrder.getStartPlace().toLowerCase().replace("纯", "").replace("coc", "").replace("soc", "") + zadOrder.getDestPlace().toLowerCase().replace("纯", "").replace("coc", "").replace("soc", "");
                // 计算两个日期相差多少天
                localDateTime = DateUtils.convertStringToLocalDateTime(zadOrder.getArriveTime());
                if(localDateTime == null){
                    continue;
                }
                Duration duration = Duration.between(localDateTime, zadOrder.getSendTime().atStartOfDay());
                long days = Math.abs(duration.toDays()); //相差的天数
                if (yearCountDto.getLineAgeList().stream().noneMatch(item -> item.getLine().equals(line) && item.getMonth() == monthValue)) {
                    LineAgeDto lineAgeDto = new LineAgeDto();
                    lineAgeDto.setLine(line);
                    lineAgeDto.setMonth(monthValue);
                    lineAgeDto.setCount(1);
                    lineAgeDto.setAge(days);
                    yearCountDto.getLineAgeList().add(lineAgeDto);
                } else {
                    yearCountDto.getLineAgeList().stream().filter(item -> item.getLine().equals(line) && item.getMonth() == monthValue).findFirst().ifPresent(item -> {
                        item.setCount(item.getCount() + 1);
                        item.setAge(item.getAge() + days);
                    });
                }
            }
            // 租箱点统计
            if (StringUtils.hasText(zadOrder.getPickPlace())) {
                if (yearCountDto.getZxdList().stream().noneMatch(item -> item.getName().equals(zadOrder.getPickPlace()))) {
                    yearCountDto.getZxdList().add(new OrderCountDto(zadOrder.getPickPlace(), 1));
                } else {
                    yearCountDto.getZxdList().stream().filter(item -> item.getName().equals(zadOrder.getPickPlace())).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
                }
            }
            // 统计相同起始站内，不同目的站的订单数
            if (StringUtils.hasText(zadOrder.getStartPlace()) && StringUtils.hasText(zadOrder.getDestPlace())) {
                String text = zadOrder.getStartPlace();
                if (yearCountDto.getSameStartPlaceList().stream().noneMatch(item -> item.getStartPlace().equals(text))) {
                    StartPlaceCountDto countDto = new StartPlaceCountDto(text);
                    countDto.getEndList().add(new OrderCountDto(zadOrder.getDestPlace(), 1));
                    yearCountDto.getSameStartPlaceList().add(countDto);
                } else {
                    String text2 = zadOrder.getDestPlace();
                    yearCountDto.getSameStartPlaceList().stream().filter(item -> item.getStartPlace().equals(text)).findFirst().flatMap(item -> item.getEndList().stream().filter(item2 -> item2.getName().equals(text2)).findFirst()).ifPresent(item2 -> item2.setCount(item2.getCount() + 1));
                }
            }
        }
        // 计算一下平均时效
        yearCountDto.calculateLineAge();
        return yearCountDto;
    }

    /**
     * 价格分析表格展示
     *
     * @return
     */
    @Override
    public List<LineAgeDto> getPriceAge(ZadOrderAnalysisQueryDto params) {
        if (StringUtils.isEmpty(params.getCreateTimeStart()) || StringUtils.isEmpty(params.getCreateTimeEnd())) {
            String yearDate = getCurrentYear() + "-01-01";
            String nextYearDate = (Integer.parseInt(params.getYear()) + 1) + "-01-01";
            params.setCreateTimeStart(DateUtils.parseLocalDateTime(yearDate).toLocalDate());
            params.setCreateTimeEnd(DateUtils.parseLocalDateTime(nextYearDate).toLocalDate());
        }
        List<LineAgeDto> lineAgeDtoList = new ArrayList<>();
        Specification<ZadOrder> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("preDepartureTime"), params.getCreateTimeStart());
            predicates.add(timeStart);
            Predicate timeEnd = criteriaBuilder.lessThan(root.get("preDepartureTime"), params.getCreateTimeEnd());
            predicates.add(timeEnd);
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<ZadOrder> zadOrders = zadOrderRepository.findAll(specification);
        for (ZadOrder zadOrder : zadOrders) {

        }
        return lineAgeDtoList;
    }

    /**
     * 业务量分析表
     */
    @Override
    public List<StartPlaceCountDto> getCountAge(ZadOrderAnalysisQueryDto params) {
        List<StartPlaceCountDto> countDtos = new ArrayList<>();
        countDtos.add(new StartPlaceCountDto("集装箱"));
        countDtos.add(new StartPlaceCountDto("国际班列"));
        countDtos.add(new StartPlaceCountDto("仓储"));
        countDtos.add(new StartPlaceCountDto("综合物流"));
        List<String> orgIds = organizationService.getChildOrgIds(params.getOrganizationId());
        if (StringUtils.isEmpty(params.getCreateTimeStart()) || StringUtils.isEmpty(params.getCreateTimeEnd())) {
            LocalDate date = LocalDate.now();
            LocalDate firstDay = date.with(TemporalAdjusters.firstDayOfMonth()); // 获取当前月的第一天
            LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth()); // 获取当前月的最后一天
            params.setCreateTimeStart(firstDay);
            params.setCreateTimeEnd(lastDay.plusDays(1));
            String startDate;
            String endDate;
            if (StringUtils.isEmpty(params.getType()) || "1".equals(params.getType())) {
                int nextYear = Integer.parseInt(params.getYear()) + 1;
                startDate = params.getYear() + "-01-01";
                params.setCreateTimeStart(LocalDate.parse(startDate, df));
                endDate = nextYear + "-01-01";
                params.setCreateTimeEnd(LocalDate.parse(endDate, df).plusDays(1));
            }
        }
        Specification<ZadOrder> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("preDepartureTime"), params.getCreateTimeStart());
            predicates.add(timeStart);
            Predicate timeEnd = criteriaBuilder.lessThan(root.get("preDepartureTime"), params.getCreateTimeEnd());
            predicates.add(timeEnd);
            // 得到当前机构及子机构的所有订单
            Expression<String> exp = root.get("organizationId");
            predicates.add(exp.in(orgIds));
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<ZadOrder> zadOrders = zadOrderRepository.findAll(specification);
        for (ZadOrder zadOrder : zadOrders) {
            String text = zadOrder.getDestPlace();
            if (StringUtils.hasText(text) && text.toLowerCase().contains("纯coc")) {
                countDtos.stream().filter(item -> item.getStartPlace().equals("集装箱")).findFirst().ifPresent(item -> {
                    if (item.getEndList().stream().noneMatch(item2 -> item2.getName().equals(zadOrder.getClientName()))) {
                        item.getEndList().add(new OrderCountDto(zadOrder.getClientName(), 1));
                    } else {
                        item.getEndList().stream().filter(item2 -> item2.getName().equals(zadOrder.getClientName())).findFirst().ifPresent(item2 -> {
                            item2.setCount(item2.getCount() + 1);
                        });
                    }
                });
            } else {
                countDtos.stream().filter(item -> item.getStartPlace().equals("国际班列")).findFirst().ifPresent(item -> {
                    if (item.getEndList().stream().noneMatch(item2 -> item2.getName().equals(zadOrder.getClientName()))) {
                        item.getEndList().add(new OrderCountDto(zadOrder.getClientName(), 1));
                    } else {
                        item.getEndList().stream().filter(item2 -> item2.getName().equals(zadOrder.getClientName())).findFirst().ifPresent(item2 -> {
                            item2.setCount(item2.getCount() + 1);
                        });
                    }
                });
            }
        }
        Specification<GhOrder> specification2 = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("pickDate"), params.getCreateTimeStart());
            predicates.add(timeStart);
            Predicate timeEnd = criteriaBuilder.lessThan(root.get("pickDate"), params.getCreateTimeEnd());
            predicates.add(timeEnd);
            // 得到当前机构及子机构的所有订单
            Expression<String> exp = root.get("organizationId");
            predicates.add(exp.in(orgIds));
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<GhOrder> ghOrders = ghOrderRepository.findAll(specification2);
        for (GhOrder ghOrder : ghOrders) {
            if (ghOrder.getBusinessCode().contains("仓储")) {
                countDtos.stream().filter(item -> item.getStartPlace().equals("仓储")).findFirst().ifPresent(item -> {
                    if (item.getEndList().stream().noneMatch(item2 -> item2.getName().equals(ghOrder.getClientName()))) {
                        item.getEndList().add(new OrderCountDto(ghOrder.getClientName(), 1));
                    } else {
                        item.getEndList().stream().filter(item2 -> item2.getName().equals(ghOrder.getClientName())).findFirst().ifPresent(item2 -> {
                            item2.setCount(item2.getCount() + 1);
                        });
                    }
                });
            } else if (ghOrder.getBusinessCode().contains("综合物流")) {
                countDtos.stream().filter(item -> item.getStartPlace().equals("综合物流")).findFirst().ifPresent(item -> {
                    if (item.getEndList().stream().noneMatch(item2 -> item2.getName().equals(ghOrder.getClientName()))) {
                        item.getEndList().add(new OrderCountDto(ghOrder.getClientName(), 1));
                    } else {
                        item.getEndList().stream().filter(item2 -> item2.getName().equals(ghOrder.getClientName())).findFirst().ifPresent(item2 -> {
                            item2.setCount(item2.getCount() + 1);
                        });
                    }
                });
            }
        }
        // 统计历史数据
        // 加上历史订单（国际班列和综合物流）
        Specification<HistoryZadOrder> specification3 = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (params.getCreateTimeStart() != null && params.getCreateTimeEnd() != null) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("blTime"), params.getCreateTimeStart());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("blTime"), params.getCreateTimeEnd().plusDays(1));
                predicates.add(timeEnd);
            }
            // 得到当前机构及子机构的所有订单
            Expression<String> exp = root.get("organizationId");
            predicates.add(exp.in(orgIds));
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<HistoryZadOrder> historyZadOrderRepositoryAll = historyZadOrderRepository.findAll(specification3);
        // 先按照柜号进行分组
        Map<String, List<HistoryZadOrder>> historyZadOrderRepositoryAllMap =
                historyZadOrderRepositoryAll.stream().filter(data -> StringUtils.hasText(data.getClientName())).collect(Collectors.groupingBy(HistoryZadOrder::getPackageNo));
        Set<String> noKeyList = historyZadOrderRepositoryAllMap.keySet();
        for (String packageNo : noKeyList) {
            HistoryZadOrder historyZadOrder = historyZadOrderRepositoryAllMap.get(packageNo).get(0);
            String text = historyZadOrder.getDestPlace();
            if (StringUtils.hasText(text) && text.toLowerCase().contains("纯coc")) {
                countDtos.stream().filter(item -> item.getStartPlace().equals("集装箱")).findFirst().ifPresent(item -> {
                    if (item.getEndList().stream().noneMatch(item2 -> item2.getName().equals(historyZadOrder.getClientName()))) {
                        item.getEndList().add(new OrderCountDto(historyZadOrder.getClientName(), 1));
                    } else {
                        item.getEndList().stream().filter(item2 -> item2.getName().equals(historyZadOrder.getClientName())).findFirst().ifPresent(item2 -> {
                            item2.setCount(item2.getCount() + 1);
                        });
                    }
                });
            } else {
                countDtos.stream().filter(item -> item.getStartPlace().equals("国际班列")).findFirst().ifPresent(item -> {
                    if (item.getEndList().stream().noneMatch(item2 -> item2.getName().equals(historyZadOrder.getClientName()))) {
                        item.getEndList().add(new OrderCountDto(historyZadOrder.getClientName(), 1));
                    } else {
                        item.getEndList().stream().filter(item2 -> item2.getName().equals(historyZadOrder.getClientName())).findFirst().ifPresent(item2 -> {
                            item2.setCount(item2.getCount() + 1);
                        });
                    }
                });
            }
        }
        // 综合物流
        Specification<HistoryGhOrder> specification4 = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (params.getCreateTimeStart() != null && params.getCreateTimeEnd() != null) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("pickTime"), params.getCreateTimeStart());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("pickTime"),
                        params.getCreateTimeEnd().plusDays(1));
                predicates.add(timeEnd);
            }
            // 得到当前机构及子机构的所有订单
            Expression<String> exp = root.get("organizationId");
            predicates.add(exp.in(orgIds));
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<HistoryGhOrder> historyGhOrderRepositoryAll = historyGhOrderRepository.findAll(specification4);
        // 按照订舱号分组
        Map<String, List<HistoryGhOrder>> historyGhOrderRepositoryAllMap =
                historyGhOrderRepositoryAll.stream().filter(data -> StringUtils.hasText(data.getClientName())).collect(Collectors.groupingBy(HistoryGhOrder::getBookNo));
        Set<String> bookNoList = historyGhOrderRepositoryAllMap.keySet();
        for (String bookNo : bookNoList) {
            HistoryGhOrder historyGhOrder = historyGhOrderRepositoryAllMap.get(bookNo).get(0);
            if (historyGhOrder.getBusinessType().contains("仓储")) {
                countDtos.stream().filter(item -> item.getStartPlace().equals("仓储")).findFirst().ifPresent(item -> {
                    if (item.getEndList().stream().noneMatch(item2 -> item2.getName().equals(historyGhOrder.getClientName()))) {
                        item.getEndList().add(new OrderCountDto(historyGhOrder.getClientName(), 1));
                    } else {
                        item.getEndList().stream().filter(item2 -> item2.getName().equals(historyGhOrder.getClientName())).findFirst().ifPresent(item2 -> {
                            item2.setCount(item2.getCount() + 1);
                        });
                    }
                });
            } else if (historyGhOrder.getBusinessType().contains("综合物流")) {
                countDtos.stream().filter(item -> item.getStartPlace().equals("综合物流")).findFirst().ifPresent(item -> {
                    if (item.getEndList().stream().noneMatch(item2 -> item2.getName().equals(historyGhOrder.getClientName()))) {
                        item.getEndList().add(new OrderCountDto(historyGhOrder.getClientName(), 1));
                    } else {
                        item.getEndList().stream().filter(item2 -> item2.getName().equals(historyGhOrder.getClientName())).findFirst().ifPresent(item2 -> {
                            item2.setCount(item2.getCount() + 1);
                        });
                    }
                });
            }
        }
        return countDtos;
    }

    @Override
    public List<LineAgeDto> clientPriceCount(ZadOrderAnalysisQueryDto params) {
        if (StringUtils.isEmpty(params.getYear())) {
            params.setYear(getCurrentYear());
        }
        // 找出所有的客户
        List<Client> clients = clientRepository.findAll();
        if (StringUtils.hasText(params.getClientId())) {
            clients = clients.stream().filter(client -> client.getId().equals(params.getClientId())).collect(Collectors.toList());
        }
        // 取出客户的ID
        List<String> clientIds = clients.stream().map(BaseEntity::getId).collect(Collectors.toList());
        Specification<LinePrice> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            // 下一年
            int nextYear = Integer.parseInt(params.getYear()) + 1;
            String startDate = params.getYear() + "-01-01";
            String endDate = nextYear + "-01-01";
            Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("startDate"), LocalDate.parse(startDate, DateTimeFormatter.ISO_DATE));
            predicates.add(timeStart);
            Predicate timeEnd = criteriaBuilder.lessThan(root.get("endDate"), LocalDate.parse(endDate, DateTimeFormatter.ISO_DATE));
            predicates.add(timeEnd);
            /*if(StringUtils.hasText(params.getClientId())){
                Predicate site = criteriaBuilder.like(root.get("id"), params.getClientId());
                predicates.add(site);
            }*/
            Expression<String> exp = root.get("belongId");
            predicates.add(exp.in(clientIds));
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<LinePrice> linePrices = linePriceRepository.findAll(specification);
        List<LineAgeDto> linePriceCountList = new ArrayList<>();
        /*// 先初始化12个月的数据
        for (int i = 1; i < 13; i++) {
            LineAgeDto dto = new LineAgeDto();
            dto.setMonth(i);
            linePriceCountList.add(dto);
        }*/
        String startPlace;
        String endPlace;
        // 循环每一条线路
        for (LinePrice linePrice : linePrices) {
            if ("应付".equals(linePrice.getFeeType())) {
                continue;
            }
            // 只统计国际班列
            if (StringUtils.hasText(linePrice.getBusinessType()) && TypeStringUtils.GJBL.equals(linePrice.getBusinessType())) {
                // 获取到起始月份
                try {
                    int month = linePrice.getStartDate().getMonthValue();
                    startPlace = linePrice.getOriginPlace().toLowerCase().replace("纯", "").replace("coc", "").replace("soc", "").trim();
                    endPlace = linePrice.getDestPlace().toLowerCase().replace("纯", "").replace("coc", "").replace("soc", "").trim();
                    String line = startPlace + endPlace;
                    if (linePriceCountList.stream().noneMatch(lineAgeDto -> lineAgeDto.getMonth() == month && lineAgeDto.getLine().equals(line))) {
                        LineAgeDto lineAgeDto = new LineAgeDto();
                        lineAgeDto.setMonth(month);
                        lineAgeDto.setLine(line);
                        lineAgeDto.setRatio(linePrice.getPrice());
                        linePriceCountList.add(lineAgeDto);
                    } else {
                        linePriceCountList.stream().filter(lineAgeDto -> lineAgeDto.getMonth() == month && lineAgeDto.getLine().equals(line)).findFirst().ifPresent(lineAgeDto -> {
                            // 相加
                            lineAgeDto.setRatio(linePrice.getPrice() + lineAgeDto.getRatio());
                        });
                    }
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
            }
        }
        linePriceCountList.sort(Comparator.comparing(LineAgeDto::getMonth));
        return linePriceCountList;
    }

    @Override
    public List<LineAgeDto> carrierPriceCount(ZadOrderAnalysisQueryDto params) {
        if (StringUtils.isEmpty(params.getYear())) {
            params.setYear(getCurrentYear());
        }
        // 找出所有的客户
        List<Carrier> carriers = carrierRepository.findAll();
        if (StringUtils.hasText(params.getCarrierId())) {
            carriers = carriers.stream().filter(carrier -> carrier.getId().equals(params.getCarrierId())).collect(Collectors.toList());
        }
        // 取出客户的ID
        List<String> carrierIds = carriers.stream().map(BaseEntity::getId).collect(Collectors.toList());
        Specification<LinePrice> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            // 下一年
            int nextYear = Integer.parseInt(params.getYear()) + 1;
            String startDate = params.getYear() + "-01-01";
            String endDate = nextYear + "-01-01";
            Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("startDate"), LocalDate.parse(startDate, DateTimeFormatter.ISO_DATE));
            predicates.add(timeStart);
            Predicate timeEnd = criteriaBuilder.lessThan(root.get("endDate"), LocalDate.parse(endDate, DateTimeFormatter.ISO_DATE));
            predicates.add(timeEnd);
            Expression<String> exp = root.get("belongId");
            predicates.add(exp.in(carrierIds));
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<LinePrice> linePrices = linePriceRepository.findAll(specification);
        List<LineAgeDto> linePriceCountList = new ArrayList<>();
        /*// 先初始化12个月的数据
        for (int i = 1; i < 13; i++) {
            LineAgeDto dto = new LineAgeDto();
            dto.setMonth(i);
            linePriceCountList.add(dto);
        }*/
        String startPlace;
        String endPlace;
        // 循环每一条线路
        for (LinePrice linePrice : linePrices) {
            if ("应收".equals(linePrice.getFeeType())) {
                continue;
            }
            // 只统计国际班列
            if (StringUtils.hasText(linePrice.getBusinessType()) && TypeStringUtils.GJBL.equals(linePrice.getBusinessType())) {
                // 获取到起始月份
                try {
                    int month = linePrice.getStartDate().getMonthValue();
                    startPlace = linePrice.getOriginPlace().toLowerCase().replace("纯", "").replace("coc", "").replace("soc", "").trim();
                    endPlace = linePrice.getDestPlace().toLowerCase().replace("纯", "").replace("coc", "").replace("soc", "").trim();
                    String line = startPlace + endPlace;
                    if (linePriceCountList.stream().noneMatch(lineAgeDto -> lineAgeDto.getMonth() == month && lineAgeDto.getLine().equals(line))) {
                        LineAgeDto lineAgeDto = new LineAgeDto();
                        lineAgeDto.setMonth(month);
                        lineAgeDto.setLine(line);
                        lineAgeDto.setRatio(linePrice.getPrice());
                        linePriceCountList.add(lineAgeDto);
                    } else {
                        linePriceCountList.stream().filter(lineAgeDto -> lineAgeDto.getMonth() == month && lineAgeDto.getLine().equals(line)).findFirst().ifPresent(lineAgeDto -> {
                            // 相加
                            lineAgeDto.setRatio(linePrice.getPrice() + lineAgeDto.getRatio());
                        });
                    }
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
            }
        }
        linePriceCountList.sort(Comparator.comparing(LineAgeDto::getMonth));
        return linePriceCountList;
    }

    // 数量盈利分析表
    @Override
    public GhOrderYearCountDto ghOrderYearCount(ZadOrderAnalysisQueryDto params) {
        GhOrderYearCountDto yearCountDto = new GhOrderYearCountDto();
        if (StringUtils.isEmpty(params.getYear())) {
            params.setYear(getCurrentYear());
        }
        List<String> orgIds = organizationService.getChildOrgIds(params.getOrganizationId());
        Specification<GhOrder> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            // 下一年
            int nextYear = Integer.parseInt(params.getYear()) + 1;
            String startDate;
            String endDate;
            if (StringUtils.isEmpty(params.getType()) || "1".equals(params.getType())) {
                startDate = params.getYear() + "-01-01";
                endDate = nextYear + "-01-01";
            } else {
                startDate = params.getCreateTimeStart().format(df);
                endDate = params.getCreateTimeEnd().plusDays(1).format(df);
            }
            Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("pickDate"), LocalDate.parse(startDate, DateTimeFormatter.ISO_DATE));
            predicates.add(timeStart);
            Predicate timeEnd = criteriaBuilder.lessThan(root.get("pickDate"), LocalDate.parse(endDate, DateTimeFormatter.ISO_DATE));
            predicates.add(timeEnd);
            // 得到当前机构及子机构的所有订单
            Expression<String> exp = root.get("organizationId");
            predicates.add(exp.in(orgIds));
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<GhOrder> ghOrders = ghOrderRepository.findAll(specification);
        // 综合物流
        yearCountDto.getOrderTypeCount().add(new OrderCountDto("总单量",
                ghOrders.stream().filter(ghOrder -> StringUtils.hasText(ghOrder.getBookNumber())).count()));
        yearCountDto.getOrderTypeCount().add(new OrderCountDto("提货线路", 0));
        yearCountDto.getOrderTypeCount().add(new OrderCountDto("派送线路", 0));
        yearCountDto.getOrderTypeCount().add(new OrderCountDto("专车", 0));
        yearCountDto.getOrderTypeCount().add(new OrderCountDto("行邮", 0));

        // 综合物流的业务类型是仓储的统计
        yearCountDto.getCommodityCount().add(new OrderCountDto("总单量", ghOrders.stream().filter(ghOrder -> StringUtils.hasText(ghOrder.getBookNumber()) && "仓储".equals(ghOrder.getBusinessCode())).count()));
        yearCountDto.getCommodityCount().add(new OrderCountDto("提货线路", 0));
        yearCountDto.getCommodityCount().add(new OrderCountDto("派送线路", 0));
        for (GhOrder ghOrder : ghOrders) {
            if (StringUtils.hasText(ghOrder.getVehicleLine())) {
                yearCountDto.getOrderTypeCount().stream().filter(item -> item.getName().equals("提货线路")).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
            }
            if (StringUtils.hasText(ghOrder.getDeliveryLine())) {
                yearCountDto.getOrderTypeCount().stream().filter(item -> item.getName().equals("派送线路")).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
            }
            if (StringUtils.hasText(ghOrder.getOriginPlace()) && ghOrder.getOriginPlace().contains("专车")) {
                yearCountDto.getOrderTypeCount().stream().filter(item -> item.getName().equals("专车")).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
            }
            if (StringUtils.hasText(ghOrder.getOriginPlace()) && !ghOrder.getOriginPlace().contains("专车")) {
                yearCountDto.getOrderTypeCount().stream().filter(item -> item.getName().equals("行邮")).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
            }
            if ("仓储".equals(ghOrder.getBusinessCode())) {
                if (StringUtils.hasText(ghOrder.getVehicleLine())) {
                    yearCountDto.getCommodityCount().stream().filter(item -> item.getName().equals("提货线路")).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
                }
                if (StringUtils.hasText(ghOrder.getDeliveryLine())) {
                    yearCountDto.getCommodityCount().stream().filter(item -> item.getName().equals("派送线路")).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
                }
            }
            if (StringUtils.hasText(ghOrder.getVehicleLine())) {
                String startPlace = ghOrder.getVehicleLine().split("-")[0];
                if (yearCountDto.getPickLineCount().stream().anyMatch(item -> item.getName().equals(startPlace))) {
                    yearCountDto.getPickLineCount().stream().filter(item -> item.getName().equals(startPlace)).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
                } else {
                    yearCountDto.getPickLineCount().add(new OrderCountDto(startPlace, 1));
                }
            }
            if (StringUtils.hasText(ghOrder.getDestPlace())) {
                if (yearCountDto.getDestPlaceCount().stream().anyMatch(item -> item.getName().equals(ghOrder.getDestPlace()))) {
                    yearCountDto.getDestPlaceCount().stream().filter(item -> item.getName().equals(ghOrder.getDestPlace())).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
                } else {
                    yearCountDto.getDestPlaceCount().add(new OrderCountDto(ghOrder.getDestPlace(), 1));
                }
            }
        }
        // 历史
        Specification<HistoryGhOrder> specification4 = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (params.getCreateTimeStart() != null && params.getCreateTimeEnd() != null) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("pickTime"), params.getCreateTimeStart());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("pickTime"),
                        params.getCreateTimeEnd().plusDays(1));
                predicates.add(timeEnd);
            }
            // 得到当前机构及子机构的所有订单
            Expression<String> exp = root.get("organizationId");
            predicates.add(exp.in(orgIds));
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<HistoryGhOrder> historyGhOrderRepositoryAll = historyGhOrderRepository.findAll(specification4);
        // 按照订舱号分组
        Map<String, List<HistoryGhOrder>> historyGhOrderRepositoryAllMap =
                historyGhOrderRepositoryAll.stream().filter(data -> StringUtils.hasText(data.getClientName())).collect(Collectors.groupingBy(HistoryGhOrder::getBookNo));
        Set<String> bookNoList = historyGhOrderRepositoryAllMap.keySet();
        for (String bookNo : bookNoList) {
            HistoryGhOrder ghOrder = historyGhOrderRepositoryAllMap.get(bookNo).get(0);
            if (StringUtils.hasText(ghOrder.getPickLine())) {
                yearCountDto.getOrderTypeCount().stream().filter(item -> item.getName().equals("提货线路")).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
            }
            if (StringUtils.hasText(ghOrder.getDeliveryLine())) {
                yearCountDto.getOrderTypeCount().stream().filter(item -> item.getName().equals("派送线路")).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
            }
            if (StringUtils.hasText(ghOrder.getStartPlace()) && ghOrder.getStartPlace().contains("专车")) {
                yearCountDto.getOrderTypeCount().stream().filter(item -> item.getName().equals("专车")).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
            }
            if (StringUtils.hasText(ghOrder.getStartPlace()) && !ghOrder.getStartPlace().contains("专车")) {
                yearCountDto.getOrderTypeCount().stream().filter(item -> item.getName().equals("行邮")).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
            }
            if ("仓储".equals(ghOrder.getBusinessType())) {
                if (StringUtils.hasText(ghOrder.getPickLine())) {
                    yearCountDto.getCommodityCount().stream().filter(item -> item.getName().equals("提货线路")).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
                }
                if (StringUtils.hasText(ghOrder.getDeliveryLine())) {
                    yearCountDto.getCommodityCount().stream().filter(item -> item.getName().equals("派送线路")).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
                }
            }
            if (StringUtils.hasText(ghOrder.getPickLine())) {
                String startPlace = ghOrder.getPickLine().split("-")[0];
                if (yearCountDto.getPickLineCount().stream().anyMatch(item -> item.getName().equals(startPlace))) {
                    yearCountDto.getPickLineCount().stream().filter(item -> item.getName().equals(startPlace)).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
                } else {
                    yearCountDto.getPickLineCount().add(new OrderCountDto(startPlace, 1));
                }
            }
            if (StringUtils.hasText(ghOrder.getEndPlace())) {
                if (yearCountDto.getDestPlaceCount().stream().anyMatch(item -> item.getName().equals(ghOrder.getEndPlace()))) {
                    yearCountDto.getDestPlaceCount().stream().filter(item -> item.getName().equals(ghOrder.getEndPlace())).findFirst().ifPresent(item -> item.setCount(item.getCount() + 1));
                } else {
                    yearCountDto.getDestPlaceCount().add(new OrderCountDto(ghOrder.getEndPlace(), 1));
                }
            }
        }
        return yearCountDto;
    }

    @Override
    public List<ProjectCountDto> ghMonthCount(ZadOrderAnalysisQueryDto params) {
        // 下一年
        if (StringUtils.isEmpty(params.getYear())) {
            params.setYear(getCurrentYear());
        }
        int nextYear = Integer.parseInt(params.getYear()) + 1;
        String startDate;
        String endDate;
        if ("1".equals(params.getType())) {
            startDate = params.getYear() + "-01-01";
            endDate = nextYear + "-01-01";
            params.setCreateTimeStart(LocalDate.parse(startDate, DateTimeFormatter.ISO_DATE));
            params.setCreateTimeEnd(LocalDate.parse(endDate, DateTimeFormatter.ISO_DATE));
        }
        if (StringUtils.hasText(params.getOrganizationId())) {
            List<String> orgIds = organizationService.getChildOrgIds(params.getOrganizationId());
            params.setOrgIdList(orgIds);
        }
        // 取出所有的汇率列表
        List<ExchangeRate> exchangeRates = rateRepository.findAll();
        List<Client> clients = clientRepository.findAll();
        List<Carrier> carriers = carrierRepository.findAll();
        List<Organization> organizations = organizationRepository.findAll();
        Specification<ZadOrder> specification = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (params.getCreateTimeStart() != null && params.getCreateTimeEnd() != null) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("preDepartureTime"), params.getCreateTimeStart());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("preDepartureTime"),
                        params.getCreateTimeEnd().plusDays(1));
                predicates.add(timeEnd);
            }
            if (params.getOrgIdList() != null && !params.getOrgIdList().isEmpty()) {
                // 得到当前机构及子机构的所有订单
                Expression<String> exp = root.get("organizationId");
                predicates.add(exp.in(params.getOrgIdList()));
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<ZadOrder> zadOrders = zadOrderRepository.findAll(specification);
        // 取出列表的id
        List<String> orderIds = zadOrders.stream().map(ZadOrder::getId).collect(Collectors.toList());
        // 通过id查找费用
        List<OrderFee> zadOrderFees = orderFeeRepository.findByOrderIdIn(orderIds);
        Specification<GhOrder> specification2 = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (params.getCreateTimeStart() != null && params.getCreateTimeEnd() != null) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("pickDate"), params.getCreateTimeStart());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("pickDate"),
                        params.getCreateTimeEnd().plusDays(1));
                predicates.add(timeEnd);
            }
            if (params.getOrgIdList() != null && !params.getOrgIdList().isEmpty()) {
                // 得到当前机构及子机构的所有订单
                Expression<String> exp = root.get("organizationId");
                predicates.add(exp.in(params.getOrgIdList()));
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<GhOrder> ghOrders = ghOrderRepository.findAll(specification2);
        // 取出列表的id
        List<String> ghOrderIds = ghOrders.stream().map(GhOrder::getId).collect(Collectors.toList());
        // 通过id查找费用
        List<OrderFee> ghOrderFees = orderFeeRepository.findByOrderIdIn(ghOrderIds);
        List<ProjectCountDto> projectCountDtos = new ArrayList<>();
        String clientName;
        String orgName;
        Client clientRecord;
        for (ZadOrder zadOrder : zadOrders) {
            String clientId = zadOrder.getClientId();
            clientRecord = clients.stream().filter(client -> client.getId().equals(clientId)).findFirst().orElse(null);
            if (clientRecord == null) {
                logger.info(String.format("国际班列【%s】找不到客户", zadOrder.getOrderNumber()));
                continue;
            } else {
                clientName = clientRecord.getName();
            }
            String orgId = zadOrder.getOrganizationId();
            orgName = zadOrder.getOrganizationName();
            String businessType = zadOrder.getBusinessCode();
            this.operateFee(zadOrderFees, zadOrder.getId(), orgId, orgName, clientId, clientName, businessType, projectCountDtos, zadOrder.getPreDepartureTime(), exchangeRates);
        }
        // 综合物流的逻辑一样
        for (GhOrder ghOrder : ghOrders) {
            String clientId = ghOrder.getClientId();
            clientRecord = clients.stream().filter(client -> client.getId().equals(clientId)).findFirst().orElse(null);
            if (clientRecord == null) {
                logger.info(String.format("综合物流【%s】找不到客户", ghOrder.getOrderNumber()));
                continue;
            } else {
                clientName = clientRecord.getName();
            }
            String orgId = ghOrder.getOrganizationId();
            orgName = ghOrder.getOrganizationName();
            String businessType = ghOrder.getBusinessCode();
            this.operateFee(ghOrderFees, ghOrder.getId(), orgId, orgName, clientId, clientName, businessType, projectCountDtos, ghOrder.getPickDate(), exchangeRates);
        }
        // 历史订单（国际班列和综合物流）的为了共用下面的汇总方法，所以需要造一份相同结构的数据
        ghOrderFees = new ArrayList<>();
        // 加上历史订单（国际班列和综合物流）
        Specification<HistoryZadOrder> specification3 = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (params.getCreateTimeStart() != null && params.getCreateTimeEnd() != null) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("blTime"), params.getCreateTimeStart());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("blTime"), params.getCreateTimeEnd().plusDays(1));
                predicates.add(timeEnd);
            }
            if (params.getOrgIdList() != null && !params.getOrgIdList().isEmpty()) {
                // 得到当前机构及子机构的所有订单
                Expression<String> exp = root.get("organizationId");
                predicates.add(exp.in(params.getOrgIdList()));
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        List<HistoryZadOrder> historyZadOrderRepositoryAll = historyZadOrderRepository.findAll(specification3);
        OrderFee orderFee;
        // 组装费用列表
        for (HistoryZadOrder historyZadOrder : historyZadOrderRepositoryAll) {
            if (TypeStringUtils.historyOutType.equals(historyZadOrder.getType())) {
                // 运费 USD
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                orderFee.setFeeCount(historyZadOrder.getTransportFee1());
                orderFee.setFeeName(TypeStringUtils.TRANSPORT_FEE);
                orderFee.setCurrency(TypeStringUtils.USD);
                orderFee.setCarrierId(getShortName(historyZadOrder.getOrganizationId(),
                        historyZadOrder.getTransportFeeCarrier(), organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                //运费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                orderFee.setFeeCount(historyZadOrder.getTransportFee2());
                orderFee.setFeeName(TypeStringUtils.TRANSPORT_FEE);
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setCarrierId(getShortName(historyZadOrder.getOrganizationId(),
                        historyZadOrder.getTransportFeeCarrier(), organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // DTHC USD
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                orderFee.setFeeCount(historyZadOrder.getDthc());
                orderFee.setCurrency(TypeStringUtils.USD);
                orderFee.setFeeName(TypeStringUtils.DTHC_FEE);
                orderFee.setCarrierId(getShortName(historyZadOrder.getOrganizationId(),
                        historyZadOrder.getDthcCarrier(), organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 报关费 USD
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                orderFee.setFeeCount(historyZadOrder.getBgFee1());
                orderFee.setCurrency(TypeStringUtils.USD);
                orderFee.setFeeName(TypeStringUtils.BAOGUAN_FEE);
                orderFee.setCarrierId(getShortName(historyZadOrder.getOrganizationId(),
                        historyZadOrder.getBgCarrier(), organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 报关费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                orderFee.setFeeCount(historyZadOrder.getBgFee2());
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setFeeName(TypeStringUtils.BAOGUAN_FEE);
                orderFee.setCarrierId(getShortName(historyZadOrder.getOrganizationId(),
                        historyZadOrder.getBgCarrier(), organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 报关续页费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                orderFee.setFeeCount(historyZadOrder.getBgFee3());
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setFeeName(TypeStringUtils.BAOGUANXUYE_FEE);
                orderFee.setCarrierId(getShortName(historyZadOrder.getOrganizationId(),
                        historyZadOrder.getBgCarrier(), organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 查验费 USD
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                orderFee.setFeeCount(historyZadOrder.getCheckFee1());
                orderFee.setCurrency(TypeStringUtils.USD);
                orderFee.setFeeName(TypeStringUtils.CHAYAN_FEE);
                orderFee.setCarrierId(getShortName(historyZadOrder.getOrganizationId(),
                        historyZadOrder.getCheckCarrier(), organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 查验费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                orderFee.setFeeCount(historyZadOrder.getCheckFee2());
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setFeeName(TypeStringUtils.CHAYAN_FEE);
                orderFee.setCarrierId(getShortName(historyZadOrder.getOrganizationId(),
                        historyZadOrder.getCheckCarrier(), organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 其他费用 USD
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                orderFee.setFeeCount(historyZadOrder.getOtherFee1());
                orderFee.setCurrency(TypeStringUtils.USD);
                orderFee.setFeeName(TypeStringUtils.OTHER_FEE);
                orderFee.setCarrierId(getShortName(historyZadOrder.getOrganizationId(),
                        historyZadOrder.getOtherCarrier(), organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 其他费用 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                orderFee.setFeeCount(historyZadOrder.getOtherFee2());
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setFeeName(TypeStringUtils.OTHER_FEE);
                orderFee.setCarrierId(getShortName(historyZadOrder.getOrganizationId(),
                        historyZadOrder.getOtherCarrier(), organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 堆存费 USD
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                orderFee.setFeeCount(historyZadOrder.getDcFee1());
                orderFee.setCurrency(TypeStringUtils.USD);
                orderFee.setFeeName(TypeStringUtils.DUICUN_FEE);
                orderFee.setCarrierId(getShortName(historyZadOrder.getOrganizationId(), historyZadOrder.getDcCarrier()
                        , organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 堆存费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                orderFee.setFeeCount(historyZadOrder.getDcFee2());
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setFeeName(TypeStringUtils.DUICUN_FEE);
                orderFee.setCarrierId(getShortName(historyZadOrder.getOrganizationId(), historyZadOrder.getDcCarrier()
                        , organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 国内费用 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                if (historyZadOrder.getDomesticFee() != null) {
                    orderFee.setFeeCount(historyZadOrder.getDomesticFee());
                }
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setFeeName(TypeStringUtils.IN_FEE);
                orderFee.setCarrierId(getShortName(historyZadOrder.getOrganizationId(),
                        historyZadOrder.getDomesticCarrier(), organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
            } else {
                // 运费 USD
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                orderFee.setFeeCount(historyZadOrder.getTransportFee1());
                orderFee.setFeeName(TypeStringUtils.TRANSPORT_FEE);
                orderFee.setCurrency(TypeStringUtils.USD);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                //运费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                orderFee.setFeeCount(historyZadOrder.getTransportFee2());
                orderFee.setFeeName(TypeStringUtils.TRANSPORT_FEE);
                orderFee.setCurrency(TypeStringUtils.RMB);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // DTHC USD
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                orderFee.setFeeCount(historyZadOrder.getDthc());
                orderFee.setCurrency(TypeStringUtils.USD);
                orderFee.setFeeName(TypeStringUtils.DTHC_FEE);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 报关费 USD
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                orderFee.setFeeCount(historyZadOrder.getBgFee1());
                orderFee.setCurrency(TypeStringUtils.USD);
                orderFee.setFeeName(TypeStringUtils.BAOGUAN_FEE);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 报关费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                orderFee.setFeeCount(historyZadOrder.getBgFee2());
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setFeeName(TypeStringUtils.BAOGUAN_FEE);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 报关续页费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                orderFee.setFeeCount(historyZadOrder.getBgFee3());
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setFeeName(TypeStringUtils.BAOGUANXUYE_FEE);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 查验费 USD
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                orderFee.setFeeCount(historyZadOrder.getCheckFee1());
                orderFee.setCurrency(TypeStringUtils.USD);
                orderFee.setFeeName(TypeStringUtils.CHAYAN_FEE);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 查验费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                orderFee.setFeeCount(historyZadOrder.getCheckFee2());
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setFeeName(TypeStringUtils.CHAYAN_FEE);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 其他费用 USD
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                orderFee.setFeeCount(historyZadOrder.getOtherFee1());
                orderFee.setCurrency(TypeStringUtils.USD);
                orderFee.setFeeName(TypeStringUtils.OTHER_FEE);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 其他费用 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                orderFee.setFeeCount(historyZadOrder.getOtherFee2());
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setFeeName(TypeStringUtils.OTHER_FEE);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 堆存费 USD
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                orderFee.setFeeCount(historyZadOrder.getDcFee1());
                orderFee.setCurrency(TypeStringUtils.USD);
                orderFee.setFeeName(TypeStringUtils.DUICUN_FEE);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 堆存费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                orderFee.setFeeCount(historyZadOrder.getDcFee2());
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setFeeName(TypeStringUtils.DUICUN_FEE);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 国内费用 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyZadOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                if (historyZadOrder.getDomesticFee() != null) {
                    orderFee.setFeeCount(historyZadOrder.getDomesticFee());
                }
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setFeeName(TypeStringUtils.IN_FEE);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
            }
        }
        // 把应付的记录通过柜号查找客户，填充到应付的客户字段
        List<HistoryZadOrder> historyZadOrderList = new ArrayList<>(historyZadOrderRepositoryAll);
        for (HistoryZadOrder zadOrder : historyZadOrderRepositoryAll) {
            if (TypeStringUtils.historyInType.equals(zadOrder.getType())) {
                clients.stream().filter(client -> client.getId().equals(zadOrder.getClientId()))
                        .findFirst()
                        .ifPresent(client -> zadOrder.setClientName(client.getName()));
            }
            if (TypeStringUtils.historyOutType.equals(zadOrder.getType())) {
                historyZadOrderList.stream().filter(order -> TypeStringUtils.historyInType.equals(order.getType()) && order.getPackageNo().equalsIgnoreCase(zadOrder.getPackageNo()))
                        .findFirst()
                        .ifPresent(order -> {
                            zadOrder.setClientId(order.getClientId());
                            zadOrder.setClientName(order.getClientName());
                        });
            }
        }
        Map<String, List<HistoryZadOrder>> map =
                historyZadOrderRepositoryAll.stream().collect(Collectors.groupingBy(historyZadOrder -> historyZadOrder.getOrganizationName() + historyZadOrder.getPackageNo().toUpperCase()));
        Set<String> keySet = map.keySet();
        for (String key : keySet) {
            List<HistoryZadOrder> historyZadOrders = map.get(key);
            HistoryZadOrder historyZadOrder = historyZadOrders.stream().filter(o -> StringUtils.hasText(o.getClientId())).findFirst().orElse(null);
            if (historyZadOrder == null) {
                continue;
            }
            // 跟这个数据相关的订单费用
            List<OrderFee> orderFeeList = new ArrayList<>();
            for (HistoryZadOrder zadOrder : historyZadOrders) {
                List<OrderFee> feeList = ghOrderFees.stream().filter(fee -> fee.getOrderId().equals(zadOrder.getId())).collect(Collectors.toList());
                for (OrderFee fee : feeList) {
                    // 把其他对象的费用关联ID都改成第一个的对象ID，目的是为了把数据库两条数据合成一条，最后的结果就是一条数据对应一个应收和应付
                    fee.setOrderId(historyZadOrder.getId());
                    orderFeeList.add(fee);
                }
            }
            this.operateFee(orderFeeList, historyZadOrder.getId(), historyZadOrder.getOrganizationId(), historyZadOrder.getOrganizationName(), historyZadOrder.getClientId(), historyZadOrder.getClientName(), historyZadOrder.getBusinessType(), projectCountDtos, historyZadOrder.getBlTime(), exchangeRates);
        }
        Specification<HistoryGhOrder> specification4 = ((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (params.getCreateTimeStart() != null && params.getCreateTimeEnd() != null) {
                Predicate timeStart = criteriaBuilder.greaterThanOrEqualTo(root.get("pickTime"), params.getCreateTimeStart());
                predicates.add(timeStart);
                Predicate timeEnd = criteriaBuilder.lessThan(root.get("pickTime"),
                        params.getCreateTimeEnd().plusDays(1));
                predicates.add(timeEnd);
            }
            if (params.getOrgIdList() != null && !params.getOrgIdList().isEmpty()) {
                // 得到当前机构及子机构的所有订单
                Expression<String> exp = root.get("organizationId");
                predicates.add(exp.in(params.getOrgIdList()));
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        });
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        List<HistoryGhOrder> historyGhOrderRepositoryAll = historyGhOrderRepository.findAll(specification4, sort);
        for (HistoryGhOrder historyGhOrder : historyGhOrderRepositoryAll) {
            if (TypeStringUtils.historyInType.equals(historyGhOrder.getType())) {
                // 运费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyGhOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                orderFee.setFeeCount(historyGhOrder.getTransportFee());
                orderFee.setFeeName(TypeStringUtils.TRANSPORT_FEE);
                orderFee.setCurrency(TypeStringUtils.RMB);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 提货费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyGhOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                orderFee.setFeeCount(historyGhOrder.getPickFee());
                orderFee.setFeeName(TypeStringUtils.TIHUO_FEE);
                orderFee.setCurrency(TypeStringUtils.RMB);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 派送费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyGhOrder.getId());
                orderFee.setType(TypeStringUtils.feeInType);
                orderFee.setFeeCount(historyGhOrder.getDeliveryFee());
                orderFee.setFeeName(TypeStringUtils.PAISONG_FEE);
                orderFee.setCurrency(TypeStringUtils.RMB);
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
            } else {
                // 派送费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyGhOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                orderFee.setFeeCount(historyGhOrder.getTransportFee());
                orderFee.setFeeName(TypeStringUtils.TRANSPORT_FEE);
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setCarrierId(getShortName(historyGhOrder.getOrganizationId(),
                        historyGhOrder.getTransportFeeCarrier(), organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 提货费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyGhOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                orderFee.setFeeCount(historyGhOrder.getPickFee());
                orderFee.setFeeName(TypeStringUtils.TIHUO_FEE);
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setCarrierId(getShortName(historyGhOrder.getOrganizationId(),
                        historyGhOrder.getPickFeeCarrier(), organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
                // 派送费 RMB
                orderFee = new OrderFee();
                orderFee.setOrderId(historyGhOrder.getId());
                orderFee.setType(TypeStringUtils.feeOutType);
                orderFee.setFeeCount(historyGhOrder.getDeliveryFee());
                orderFee.setFeeName(TypeStringUtils.PAISONG_FEE);
                orderFee.setCurrency(TypeStringUtils.RMB);
                orderFee.setCarrierId(getShortName(historyGhOrder.getOrganizationId(),
                        historyGhOrder.getDeliveryFeeCarrier(), organizations, carriers));
                if (BigDecimal.ZERO.compareTo(BigDecimal.valueOf(orderFee.getFeeCount())) != 0) {
                    ghOrderFees.add(orderFee);
                }
            }
        }
        // 填充客户
        List<HistoryGhOrder> historyGhOrderList = new ArrayList<>(historyGhOrderRepositoryAll);
        for (HistoryGhOrder historyGhOrder : historyGhOrderRepositoryAll) {
            if (TypeStringUtils.historyInType.equals(historyGhOrder.getType())) {
                clients.stream().filter(client -> client.getId().equals(historyGhOrder.getClientId()))
                        .findFirst()
                        .ifPresent(client -> historyGhOrder.setClientName(client.getName()));
            }
            if (TypeStringUtils.historyOutType.equals(historyGhOrder.getType())) {
                historyGhOrderList.stream().filter(order -> TypeStringUtils.historyInType.equals(order.getType()) && order.getBookNo().equalsIgnoreCase(historyGhOrder.getBookNo()))
                        .findFirst()
                        .ifPresent(order -> {
                            historyGhOrder.setClientId(order.getClientId());
                            historyGhOrder.setClientName(order.getClientName());
                        });
            }
        }
        Map<String, List<HistoryGhOrder>> map1 =
                historyGhOrderRepositoryAll.stream().collect(Collectors.groupingBy(historyGhOrder -> historyGhOrder.getOrganizationName() + historyGhOrder.getBookNo().trim().toUpperCase()));
        keySet = map1.keySet();
        for (String key : keySet) {
            List<HistoryGhOrder> historyGhOrders = map1.get(key);
            HistoryGhOrder historyGhOrder = historyGhOrders.stream().filter(o -> StringUtils.hasText(o.getClientId())).findFirst().orElse(null);
            if (historyGhOrder == null) {
                continue;
            }
            // 跟这个数据相关的订单费用
            List<OrderFee> orderFeeList = new ArrayList<>();
            for (HistoryGhOrder ghOrder : historyGhOrders) {
                List<OrderFee> feeList = ghOrderFees.stream().filter(fee -> fee.getOrderId().equals(ghOrder.getId())).collect(Collectors.toList());
                for (OrderFee fee : feeList) {
                    // 把其他对象的费用关联ID都改成第一个的对象ID，目的是为了把数据库两条数据合成一条，最后的结果就是一条数据对应一个应收和应付
                    fee.setOrderId(historyGhOrder.getId());
                    orderFeeList.add(fee);
                }
            }
            this.operateFee(orderFeeList, historyGhOrder.getId(), historyGhOrder.getOrganizationId(), historyGhOrder.getOrganizationName(), historyGhOrder.getClientId(), historyGhOrder.getClientName(), historyGhOrder.getBusinessType(), projectCountDtos, historyGhOrder.getPickTime(), exchangeRates);
        }
        List<ProjectCountDto> newList = new ArrayList<>();
        ProjectCountDto total = new ProjectCountDto();
        total.setClient("总计");
        total.setClientId("1");
        total.setCarrier("总计");
        for (ProjectCountDto projectCountDto : projectCountDtos) {
            // 应收
            total.setIncomeTransportFeeRmb(total.getIncomeTransportFeeRmb() + projectCountDto.getIncomeTransportFeeRmb());
            total.setIncomeTransportFeeUsd(total.getIncomeTransportFeeUsd() + projectCountDto.getIncomeTransportFeeUsd());
            total.setIncomeOtherFeeRmb(total.getIncomeOtherFeeRmb() + projectCountDto.getIncomeOtherFeeRmb());
            total.setIncomeOtherFeeUsd(total.getIncomeOtherFeeUsd() + projectCountDto.getIncomeOtherFeeUsd());
            projectCountDto.setTotalIncomeRmb(projectCountDto.getIncomeTransportFeeRmb() + projectCountDto.getIncomeOtherFeeRmb());
            projectCountDto.setTotalIncomeUsd(projectCountDto.getIncomeTransportFeeUsd() + projectCountDto.getIncomeOtherFeeUsd());
            total.setTotalIncomeRmb(total.getTotalIncomeRmb() + projectCountDto.getTotalIncomeRmb());
            total.setTotalIncomeUsd(total.getTotalIncomeUsd() + projectCountDto.getTotalIncomeUsd());
            // 按照汇率算出来的人名币
            total.setIncomeTransportFeeUsdToRmb(total.getIncomeTransportFeeUsdToRmb() + projectCountDto.getIncomeTransportFeeUsdToRmb());
            total.setIncomeOtherFeeUsdToRmb(total.getIncomeOtherFeeUsdToRmb() + projectCountDto.getIncomeOtherFeeUsdToRmb());
            // 应付
            total.setPayTransportFeeRmb(total.getPayTransportFeeRmb() + projectCountDto.getPayTransportFeeRmb());
            total.setPayTransportFeeUsd(total.getPayTransportFeeUsd() + projectCountDto.getPayTransportFeeUsd());
            total.setPayOtherFeeRmb(total.getPayOtherFeeRmb() + projectCountDto.getPayOtherFeeRmb());
            total.setPayOtherFeeUsd(total.getPayOtherFeeUsd() + projectCountDto.getPayOtherFeeUsd());
            projectCountDto.setTotalPayRmb(projectCountDto.getPayTransportFeeRmb() + projectCountDto.getPayOtherFeeRmb());
            projectCountDto.setTotalPayUsd(projectCountDto.getPayTransportFeeUsd() + projectCountDto.getPayOtherFeeUsd());
            total.setTotalPayRmb(total.getTotalPayRmb() + projectCountDto.getTotalPayRmb());
            total.setTotalPayUsd(total.getTotalPayUsd() + projectCountDto.getTotalPayUsd());
            // 按照汇率算出来的人名币
            total.setPayTransportFeeUsdToRmb(total.getPayTransportFeeUsdToRmb() + projectCountDto.getPayTransportFeeUsdToRmb());
            total.setPayOtherFeeUsdToRmb(total.getPayOtherFeeUsdToRmb() + projectCountDto.getPayOtherFeeUsdToRmb());
            // 计算利润
            projectCountDto.calAssets();
            // 格式化
            projectCountDto.format();
        }
        // 计算total的利润
        total.calAssets();
        // 格式化
        total.format();
        // 按照客户加业务类型排序
        Map<String, List<ProjectCountDto>> listMap = projectCountDtos.stream().collect(Collectors.groupingBy(projectCountDto -> projectCountDto.getClient() + projectCountDto.getBusinessType()));
        listMap.forEach((client, list) -> {
            double incomeTransportRmb = 0d;
            double incomeTransportUsd = 0d;
            double incomeOtherRmb = 0d;
            double incomeOtherUsd = 0d;
            double incomeTotalTransportRmb = 0d;
            double incomeTotalTransportUsd = 0d;
            double aseets = 0d;
            // 合并一下相同客户，相同业务类型的金额
            for (ProjectCountDto projectCountDto : list) {
                incomeTransportRmb += projectCountDto.getIncomeTransportFeeRmb();
                incomeTransportUsd += projectCountDto.getIncomeTransportFeeUsd();
                incomeOtherRmb += projectCountDto.getIncomeOtherFeeRmb();
                incomeOtherUsd += projectCountDto.getIncomeOtherFeeUsd();
                incomeTotalTransportRmb += projectCountDto.getTotalIncomeRmb();
                incomeTotalTransportUsd += projectCountDto.getTotalIncomeUsd();
                aseets += projectCountDto.getCurrentAssets();
            }
            for (ProjectCountDto projectCountDto : list) {
                // 相同的客户，相同的业务类型，数据合并，前端展示合并单元格使用
                projectCountDto.setIncomeTransportFeeRmb(incomeTransportRmb);
                projectCountDto.setIncomeTransportFeeUsd(incomeTransportUsd);
                projectCountDto.setIncomeOtherFeeRmb(incomeOtherRmb);
                projectCountDto.setIncomeOtherFeeUsd(incomeOtherUsd);
                projectCountDto.setTotalIncomeRmb(incomeTotalTransportRmb);
                projectCountDto.setTotalIncomeUsd(incomeTotalTransportUsd);
                projectCountDto.setCurrentAssets(aseets);
                // 格式化
                projectCountDto.format();
            }
            newList.addAll(list);
        });
        // 加入汇总
        newList.add(total);
        // 过滤供应商为空的数据
        return newList.stream().filter(projectCountDto -> StringUtils.hasText(projectCountDto.getCarrier())).collect(Collectors.toList());
    }

    private String getShortName(String orgId, String name, List<Organization> organizations, List<Carrier> carriers) {
        Organization orElse = organizations.stream().filter(organization -> organization.getId().equals(orgId))
                .findFirst().orElse(null);
        if (orElse == null) {
            return name;
        }
        List<Carrier> carrierList = carriers.stream().filter(carrier -> carrier.getOrganizationId().equals(orgId)).collect(Collectors.toList());
        if (carrierList.size() == 0) {
            return name;
        }
        Carrier anElse = carrierList.stream().filter(carrier -> carrier.getFullName().equals(name)).findFirst().orElse(null);
        if (anElse == null) {
            return name;
        }
        return anElse.getName();
    }

    private void operateFee(List<OrderFee> totalOrderFees, String orderId, String orgId, String orgName, String clientId, String clientName, String businessType, List<ProjectCountDto> projectCountDtos, LocalDate localDate, List<ExchangeRate> exchangeRates) {
        // 过滤出订单的费用
        List<OrderFee> orderFees = totalOrderFees.stream().filter(orderFee -> orderFee.getOrderId().equals(orderId)).collect(Collectors.toList());
        if (orderFees.size() > 0) {
            for (OrderFee orderFee : orderFees) {
                if (TypeStringUtils.feeInType.equals(orderFee.getType())) {
                    if (StringUtils.isEmpty(clientId)) {
                        return;
                    }
                    // 在projectCountDtos中找到相同的clientId，相同的业务类型，相同的机构
                    ProjectCountDto projectCountDto = projectCountDtos.stream().filter(dto -> StringUtils.hasText(dto.getClientId()) && dto.getClientId().equals(clientId) && dto.getOrgId().equals(orgId) && dto.getBusinessType().equals(businessType)).findFirst().orElse(null);
                    if (projectCountDto == null) {
                        // 新建一条记录
                        projectCountDto = new ProjectCountDto();
                        projectCountDto.setClientId(clientId);
                        projectCountDto.setClient(clientName);
                        projectCountDto.setBusinessType(businessType);
                        projectCountDto.setOrgId(orgId);
                        projectCountDto.setOrgName(orgName);
                        // 初始化费用
                        this.initIncomeFee(orderFee, projectCountDto, localDate, exchangeRates);
                        // 添加到集合
                        projectCountDtos.add(projectCountDto);
                    } else {
                        // 累加不同的费用
                        this.addIncomeFee(orderFee, projectCountDto, localDate, exchangeRates);
                    }
                } else if (TypeStringUtils.feeOutType.equals(orderFee.getType())) {
                    String carrier = orderFee.getCarrierId();
                    if (StringUtils.isEmpty(carrier)) {
                        continue;
                    }
                    /*logger.info("%s:%s:%s%n", orderFee.getFeeName(), orderFee.getCarrierId(),
                            orderFee.getFeeCount());*/
                    // 在projectCountDtos中找到相同的clientId，相同的业务类型，相同的机构，相同供应商的记录
                    ProjectCountDto projectCountDto = projectCountDtos.stream().filter(dto -> StringUtils.hasText(dto.getClientId()) && dto.getClientId().equals(clientId) && dto.getOrgId().equals(orgId) && dto.getBusinessType().equals(businessType) && carrier.equals(dto.getCarrier())).findFirst().orElse(null);
                    if (projectCountDto == null) {
                        projectCountDto = new ProjectCountDto();
                        projectCountDto.setClientId(clientId);
                        projectCountDto.setClient(clientName);
                        projectCountDto.setBusinessType(businessType);
                        projectCountDto.setOrgId(orgId);
                        projectCountDto.setOrgName(orgName);
                        projectCountDto.setCarrier(carrier);
                        // 初始化费用
                        this.initPayFee(orderFee, projectCountDto, localDate, exchangeRates);
                        // 添加到集合
                        projectCountDtos.add(projectCountDto);
                    } else {
                        // 累加不同的费用
                        this.addPayFee(orderFee, projectCountDto, localDate, exchangeRates);
                    }
                }
            }
        }
    }


    private void addIncomeFee(OrderFee orderFee, ProjectCountDto projectCountDto, LocalDate localDate, List<ExchangeRate> exchangeRates) {
        // 累加应收费用 分运费和杂费
        if (TypeStringUtils.TRANSPORT_FEE.equals(orderFee.getFeeName())) {
            // 再分人名币和美元
            if (TypeStringUtils.RMB.equals(orderFee.getCurrency())) {
                projectCountDto.setIncomeTransportFeeRmb(projectCountDto.getIncomeTransportFeeRmb() + orderFee.getFeeCount());
            } else {
                projectCountDto.setIncomeTransportFeeUsd(projectCountDto.getIncomeTransportFeeUsd() + orderFee.getFeeCount());
                // 需要根据当时汇率，算出人名币
                if (localDate != null) {
                    exchangeRates.stream().filter(rate -> (rate.getStartDate().isBefore(localDate) || rate.getStartDate().equals(localDate)) && (rate.getEndDate().isAfter(localDate) || rate.getEndDate().equals(localDate))).findFirst().ifPresent(exchangeRate -> {
                        // 美金乘以汇率=人名币
                        projectCountDto.setIncomeTransportFeeUsdToRmb(orderFee.getFeeCount() * exchangeRate.getRate() + projectCountDto.getIncomeTransportFeeUsdToRmb());
                    });
                }
            }
        } else {
            // 再分人名币和美元
            if (TypeStringUtils.RMB.equals(orderFee.getCurrency())) {
                projectCountDto.setIncomeOtherFeeRmb(projectCountDto.getIncomeOtherFeeRmb() + orderFee.getFeeCount());
            } else {
                projectCountDto.setIncomeOtherFeeUsd(projectCountDto.getIncomeOtherFeeUsd() + orderFee.getFeeCount());
                // 需要根据当时汇率，算出人名币
                if (localDate != null) {
                    exchangeRates.stream().filter(rate -> (rate.getStartDate().isBefore(localDate) || rate.getStartDate().equals(localDate)) && (rate.getEndDate().isAfter(localDate) || rate.getEndDate().equals(localDate))).findFirst().ifPresent(exchangeRate -> {
                        // 美金乘以汇率=人名币
                        projectCountDto.setIncomeOtherFeeUsdToRmb(orderFee.getFeeCount() * exchangeRate.getRate() + projectCountDto.getIncomeOtherFeeUsdToRmb());
                    });
                }
            }
        }
    }

    private void addPayFee(OrderFee orderFee, ProjectCountDto projectCountDto, LocalDate localDate, List<ExchangeRate> exchangeRates) {
        // 累加应收费用 分运费和杂费
        if (TypeStringUtils.TRANSPORT_FEE.equals(orderFee.getFeeName())) {
            // 再分人名币和美元
            if (TypeStringUtils.RMB.equals(orderFee.getCurrency())) {
                projectCountDto.setPayTransportFeeRmb(projectCountDto.getPayTransportFeeRmb() + orderFee.getFeeCount());
            } else {
                projectCountDto.setPayTransportFeeUsd(projectCountDto.getPayTransportFeeUsd() + orderFee.getFeeCount());
                // 需要根据当时汇率，算出人名币
                if (localDate != null) {
                    exchangeRates.stream().filter(rate -> (rate.getStartDate().isBefore(localDate) || rate.getStartDate().equals(localDate)) && (rate.getEndDate().isAfter(localDate) || rate.getEndDate().equals(localDate))).findFirst().ifPresent(exchangeRate -> {
                        // 美金乘以汇率=人名币
                        projectCountDto.setPayTransportFeeUsdToRmb(orderFee.getFeeCount() * exchangeRate.getRate() + projectCountDto.getPayTransportFeeUsdToRmb());
                    });
                }
            }
        } else {
            // 再分人名币和美元
            if (TypeStringUtils.RMB.equals(orderFee.getCurrency())) {
                projectCountDto.setPayOtherFeeRmb(projectCountDto.getPayOtherFeeRmb() + orderFee.getFeeCount());
            } else {
                projectCountDto.setPayOtherFeeUsd(projectCountDto.getPayOtherFeeUsd() + orderFee.getFeeCount());
                // 需要根据当时汇率，算出人名币
                if (localDate != null) {
                    exchangeRates.stream().filter(rate -> (rate.getStartDate().isBefore(localDate) || rate.getStartDate().equals(localDate)) && (rate.getEndDate().isAfter(localDate) || rate.getEndDate().equals(localDate))).findFirst().ifPresent(exchangeRate -> {
                        // 美金乘以汇率=人名币
                        projectCountDto.setPayOtherFeeUsdToRmb(orderFee.getFeeCount() * exchangeRate.getRate() + projectCountDto.getPayOtherFeeUsdToRmb());
                    });
                }
            }
        }
    }

    private void initIncomeFee(OrderFee orderFee, ProjectCountDto projectCountDto, LocalDate localDate, List<ExchangeRate> exchangeRates) {
        // 设置费用 分运费和杂费
        if (TypeStringUtils.TRANSPORT_FEE.equals(orderFee.getFeeName())) {
            // 再分人名币和美元
            if (TypeStringUtils.RMB.equals(orderFee.getCurrency())) {
                projectCountDto.setIncomeTransportFeeRmb(orderFee.getFeeCount());
            } else {
                projectCountDto.setIncomeTransportFeeUsd(orderFee.getFeeCount());
                // 需要根据当时汇率，算出人名币
                if (localDate != null) {
                    exchangeRates.stream().filter(rate -> (rate.getStartDate().isBefore(localDate) || rate.getStartDate().equals(localDate)) && (rate.getEndDate().isAfter(localDate) || rate.getEndDate().equals(localDate))).findFirst().ifPresent(exchangeRate -> {
                        // 美金乘以汇率=人名币
                        projectCountDto.setIncomeTransportFeeUsdToRmb(orderFee.getFeeCount() * exchangeRate.getRate() + projectCountDto.getIncomeTransportFeeUsdToRmb());
                    });
                }
            }
        } else {
            // 再分人名币和美元
            if (TypeStringUtils.RMB.equals(orderFee.getCurrency())) {
                projectCountDto.setIncomeOtherFeeRmb(orderFee.getFeeCount());
            } else {
                projectCountDto.setIncomeOtherFeeUsd(orderFee.getFeeCount());
                // 需要根据当时汇率，算出人名币
                if (localDate != null) {
                    exchangeRates.stream().filter(rate -> (rate.getStartDate().isBefore(localDate) || rate.getStartDate().equals(localDate)) && (rate.getEndDate().isAfter(localDate) || rate.getEndDate().equals(localDate))).findFirst().ifPresent(exchangeRate -> {
                        // 美金乘以汇率=人名币
                        projectCountDto.setIncomeOtherFeeUsdToRmb(orderFee.getFeeCount() * exchangeRate.getRate() + projectCountDto.getIncomeOtherFeeUsdToRmb());
                    });
                }
            }
        }
    }

    private void initPayFee(OrderFee orderFee, ProjectCountDto projectCountDto, LocalDate localDate, List<ExchangeRate> exchangeRates) {
        // 设置费用 分运费和杂费
        if (TypeStringUtils.TRANSPORT_FEE.equals(orderFee.getFeeName())) {
            // 再分人名币和美元
            if (TypeStringUtils.RMB.equals(orderFee.getCurrency())) {
                projectCountDto.setPayTransportFeeRmb(orderFee.getFeeCount());
            } else {
                projectCountDto.setPayTransportFeeUsd(orderFee.getFeeCount());
                // 需要根据当时汇率，算出人名币
                if (localDate != null) {
                    exchangeRates.stream().filter(rate -> (rate.getStartDate().isBefore(localDate) || rate.getStartDate().equals(localDate)) && (rate.getEndDate().isAfter(localDate) || rate.getEndDate().equals(localDate))).findFirst().ifPresent(exchangeRate -> {
                        // 美金乘以汇率=人名币
                        projectCountDto.setPayTransportFeeUsdToRmb(orderFee.getFeeCount() * exchangeRate.getRate() + projectCountDto.getPayTransportFeeUsdToRmb());
                    });
                }
            }
        } else {
            // 再分人名币和美元
            if (TypeStringUtils.RMB.equals(orderFee.getCurrency())) {
                projectCountDto.setPayOtherFeeRmb(orderFee.getFeeCount());
            } else {
                projectCountDto.setPayOtherFeeUsd(orderFee.getFeeCount());
                // 需要根据当时汇率，算出人名币
                if (localDate != null) {
                    exchangeRates.stream().filter(rate -> (rate.getStartDate().isBefore(localDate) || rate.getStartDate().equals(localDate)) && (rate.getEndDate().isAfter(localDate) || rate.getEndDate().equals(localDate))).findFirst().ifPresent(exchangeRate -> {
                        // 美金乘以汇率=人名币
                        projectCountDto.setPayOtherFeeUsdToRmb(orderFee.getFeeCount() * exchangeRate.getRate() + projectCountDto.getPayOtherFeeUsdToRmb());
                    });
                }
            }
        }
    }

    @Data
    public static class ClientData {
        private String id;// 汇总列
        private String name;
        private double amount;
        private double inTransportFeeOfRMB;
        private double inTransportFeeOfUSD;
        private double inOtherOfRMB;
        private double inOtherOfUSD;
        private double profit;

        public void addInFee(String currency, String feeName, double fee) {

            if ("美元".equals(currency) || "USD".equals(currency)) {
                if (feeName.contains("运输费")) {
                    this.inTransportFeeOfUSD = this.inTransportFeeOfUSD + fee;
                } else {
                    this.inOtherOfUSD = this.inOtherOfUSD + fee;
                }
            } else if ("人民币".equals(currency) || "RMB".equals(currency)) {
                if (feeName.contains("运输费")) {
                    this.inTransportFeeOfRMB = this.inTransportFeeOfRMB + fee;
                } else {
                    this.inOtherOfRMB = this.inOtherOfRMB + fee;
                }
            }
        }
    }
}
